Cross-Platform Development with Delphi 10.2 & FireMonkey. for Windows, Mac OS X (macos) & Linux. Harry Stahl

Size: px
Start display at page:

Download "Cross-Platform Development with Delphi 10.2 & FireMonkey. for Windows, Mac OS X (macos) & Linux. Harry Stahl"

Transcription

1

2 Cross-Platform Development with Delphi 10.2 & FireMonkey for Windows, Mac OS X (macos) & Linux Harry Stahl

3 Author: Harry Stahl Publisher: Harry Stahl City: Bonn, Germany Copyright (2017), All rights reserved Delphi and FireMonkey are registered trademarks of Embarcadero. Apple, OS X, ios, ipad, and iphone are registered trademarks of Apple. Windows is a registered trademark of Microsoft. If I have used in this book a trademark - without referring to the owner, please inform me. I will revise it immediately. First edition

4 TABLE OF CONTENTS Foreword Introduction About the book About the author Contact information Chapter 1: What is FireMonkey? Chapter 2: How to use the FireMonkey components Section 1: Getting Started Section 2: New FireMonkey project FireMonkey desktop application (Multi Device Application) Using the Multi Device Designer (Fire UI) Form inheritance with the Multi Device Designer Reverting to inherited settings Creating a platform-specific event handler with the Multi-Device Designer Section 3: A first FMX-program (analog clock) Section 4: Selected FireMonkey components TButton (with Trimming) TEdit (without PasswordChar) TExpander TForm (furthermore with caption) TFrame TPanel TRectangle TCheckbox, TRadioButton (IsChecked) TGroupBox with TRadioButtons

5 TSwitch TImage TImageControl TImageViewer TImageViewer (to use with Livebindings Designer) TLabel (new property FontColor) TPathLabel TPath TImageList (not available - but compensation possible) TListBox (no TCheckListbox, but ShowCheckboxes) All Components (except the form) Several Components (Properties with additional type-qualifying) TMenuItem (without ImageIndex) TMainMenu (Handling MAC Menus) TMemo (CaretPosition, no Modified, FindNext-replacement) TDropTarget (how drag & drop works in FireMonkey) TRichEdit (not available - but possible for replacement via 3rd-party) TPageControl (Not available - but replacement available) TStringGrid (works different) TGrid (Image and other elements in the Grid) TStringGrid-alternative (TMSFMXGrid) THeader (not sections, but items) THeaderControl (is not available under FireMonkey) TProgressBar (not "position" but value) TTabControl (no Ownerdraw) TTrackbar (helpful property "tracking") TSpeedButton (without Bitmap) TStatusbar (a way to compensate the missing "Panels") MessageDlg (e.g. not directly usable with mtwarning) Section 5: The FireMonkey Style-Designer a) Using the Styles Editor

6 b) Styles in FireMonkey - an overview c) How to convert VCL Styles to FireMonkey Styles d) Using FireMonkey Styles e) Understanding FireMonkey-Styles Chapter 3: Tips and tricks for Cross-Platform Development Section 1: Starting other programs Section 2: Get the program directory and program data directory Section 3: Catch to the program passed start-up parameters Section 4: "Hello World" - Multilingual programs and new markets Section 5: Apply sandboxing and Entitlements properly Section 6: Using MAC APIs (POSIX, CORE and Cocoa) in Delphi Chapter 4: Requirements for Cross-Platform Development Section 1: Setting up Windows PC and MAC PC Section 2: Enabling MAC OSX Platform Section 3: Provisioning and deployment (MAC) 1. Submission to the APPLE App Store 2. How to create a.dmg file for distribution outside the Apple App Store 3. How to create your own setup package with the Application Developer ID / Installer a) Hot to request a Developer ID certificate and an Application Developer Installer ID b) Working with the code-signing tool and Package Maker Chapter 5: Cross-Platform development with Linux Section 1: Setting up Windows and Linux-PC Section 2: Enabling the Linux-Platform

7 Section 3: Provisioning and deployment (Linux) Section 4: A first Linux-Console-Application Section 5: Linux-Server-Console-Application and Client-Application Section 6: Create an Application as Service (Daemon) Section 7: Delphi units for Linux Chapter 6: Working with Graphics in FireMonkey 1. FireMonkey TBitmap versus Windows TBitmap 2. TBitmapData instead of ScanLine for bitmap manipulation 3. How to change the alpha channel of a TBitmap 4. How to draw on the canvas of a bitmap 5. How to turn graphics, flip, invert or color to gray 6. How to draw a bitmap scaled Chapter 7: 3D-Programming Section 1: Overview 1. 3D-Objects 2. Cameras 3. Screen Projections 4. Rotations 5. Light 6. Materials Section 2: The 3D Coordinate System Section 3: 3D-Application "Atomic Model" Section 4: 3D-Application "Solar Model" Chapter 8: Animations, Transitions and Effects Chapter 9: Sending and receiving messages with the TMessageManager

8 Section 1: Simple Messaging-Demo Section 2: Enhanced Messaging-Demo Chapter 10: Useful third-party components for FireMonkey 1. TMS-Components 2. Report-generator: FastReport FMX 3. RemObjects-Application Framework (Hydra) 4. Other components Chapter 11 How to - tips & tricks for FMX R1... Get the display resolution? R2... Check whether the Escape, Ctrl or Alt key is pressed R3... Use folder names under Windows and MAC properly R4... Use search-mask for "all files" in Windows and MAC OS X properly R5... Avoid looping symlink folders (Alias) R6... In which situations file symlinks functions play a role otherwise R7... Determine the control under the mouse position R8... Find out on which MAC OS X operating system the program is running R9 Get the current user name in Mac OS X / Linux / Windows R10 Send files as an attachment of an with the system mail program R11 Provide the user with help-files under Win & MAC R12... Drag and drop text from external source (eg browser) to a TEdit box R13... Store additional information in standard objects R14 Using ActiveControl R15 Replace OnDrawItem event of the ListBox from VCL with the OnPainting event of the TListBoxItems R16 Load Bitmap from resource file (for retina display)

9 R17 Swap items in a listbox R18 Swap items in a Listbox via Drag & Drop R19 Using FMX functions in a VCL application via DLL R20 Draw text in TGrid right or centered R21 Draw text in TStringGrid right or centered R22 Working with the "visible" property of controls R23 Prevent unintended shortening of TLabel text R24... How to show a pop-up menu at a special position R25 Determine the document directory R26 Improve the font quality (especially on Windows) R27 Select a folder with a dialog R28... Let a column in a string grid occupy the remaining space R29... Create missing components with Frames R30... Moving controls at runtime in the form Chapter 12: Outlook

10 Foreword This book is not for beginners of programming, but for experienced VCLdevelopers, who want to start with FireMonkey now or for those who are already working with FireMonkey and searching for some problem-solutions. Experienced users who previously developed for Windows have - when migrating to FireMonkey - a series of questions that sometimes seems to be difficult to find the answers. First of all, it needs to find out the establishment of the connection between Windows PC and the MAC or Linux and various setting dialogs. There are often only small differences between FireMonkey- and VCL components, which causes failing in development work. It costs a lot of time to find the differences. This is why I have written this book which explains the small and large differences among the most important of the well-known VCL components. The use of FireMonkey components makes especially more sense if they are used for cross-platform development. But under Windows and e.g. the MAC some functions are completely different, for example passing parameters at the start of the program. To save your time to search, this book provides you some of the answers you need. If the MAC or Linux is new to you or you have no basic information about the handling of files, available storage locations or required developer tools, you will find all of them (at least the most important of information) in this book. A new chapter in this book is about 3D-programming. Here you will find the basic understanding and some easy sample-applications. If you have any suggestions on the topic, please write an to the author. Just as an information: This book is not about the topic "databases". This is due to the personal circumstance that the author doesn't use the Delphi database

11 components, but instead of this a own solution for the work with "databases". September 2017, Bonn

12 Introduction The Internet is a blessing and a curse. You will find everything, but at the same time you are lost. In addition to searching in the internet, personal studies on the sources of Delphi and the MAC API or Linux libraries were necessary to introduce the solutions offered in this book. About the book This book will be available first only in a printed version. To read the book: If you have not set up your Mac or your Linux-PC to work with Delphi yet, you may start with the relevant chapter (Chapter 4 for the MAC and chapter 5 for Linux). If you have already completed the setup, you can just start reading it from the beginning. About the author I have been developing software for a certain long time. Starting with Turbo Pascal version 3.0 in the eighties, I then bought 5.0 Turbo Pascal for 700 DM which was at that time quite expensive for me. Apart from a short detour to Visual Basic, I stay faithful to Delphi with all versions from number 1 to the current version Delphi Tokyo (10.2). By now I've written dozens of programs with Delphi. One can develop robust and sophisticated programs with Delphi, which is confirmed by more than 5,000 customers with 10,000 users of mine. Contact information You can find my general web page at and a special site for developers at where you will also find a brief description of some of my tools that can you assist in program development.

13 You can also reach me by

14 Chapter 1: What is FireMonkey? FireMonkey, usually abbreviated as "FMX", is a software component library or vector-based framework, which allows cross-platform application development for Windows, MAC OS X (or "macos"), Linux, ios and Android, often with the same source code. The first FMX version was released with XE2, with XE3 followed a extended FMX version, which was often called "FireMonkey 2". Since then FMX has been heavily reworked with every Delphi version, so the developer often had to make a number of adjustments when switching to the latest FMX version. Fortunately the functionality of FMX increased with every new Delphi-version, so that today we have a very powerful framework, with which you can do not only everything that is possible with the VCL, but also much more. All components are freely rotatable and individually scalable. There are also a number of 3D components that can be used to write 3D programs. Finally, the effects and animations are to be mentioned, which give FMX another unique feature The representation of the components is supported by the GPU (Graphic Processing Unit), which makes the output faster and more fluid. Under Windows, the GPU is addressed with DirectX, under Mac with OpenGL and under ios / Android with OpenGL / ES. History FireMonkey was originally developed by Eugene Kryukov (company KSDEV, Uland-UDE in Russia). The product was known as VGScene. In 2011 the framework was purchased by Embarcadero and integrated in Delphi XE2 as a new framework, in addition to VCL. From XE3 it is only from the enterprise version on an integral part of Delphi, for the professional version you have to purchase it separately as a so-called mobile pack. Since Delphi 10 Berlin you can create 64-bit applications for Windows and also for IOS, for Mac and Android it remains so far with the 32-bit version. Starting with Delphi 10.2 Tokyo, the Linux platform (64-bit) is also supported, but only for the creation of console applications.

15 Outlook In relation to the VCL platform, the main innovations and enhancements are found now at FMX. There are always new components and features added to the components. In this respect I see here the future of software development with Delphi. Since May 2017, with the "FMXLinux" Add-on, we have also a possibility to develop Linux applications for the desktop with Delphi (more info on fmxlinux: So, do not be surprised if you already see some screenshots of Linux desktop programs here in the book. These were created with Delphi and the FMXLinux Add-on and look just better, as result displays in console windows.

16 Chapter 2: How to use the FireMonkey components Section 1: Getting Started My books for XE7 and earlier were more about removing the stumbling blocks if you plan to convert your previously developed VCL components into a FireMonkey program or start new projects with FireMonkey. This is still the subject of the book, but the new components and abilities of the FMX framework are described more extensively, for example in the area of 3D programming. To get a first impression, check out the included program examples, which give a good overview. For example, open the included demo "ControlsDemo". The FireMonkey demos can be found in Delphi Tokyo via the start page: The folder "Object Pascal" will take you to the sub-folder "Multi-Device Samples". In the subfolder "User Interface" you will find 28 sample projects which gives you a good overview to FMX.

17 If you want to get help in programming to convert existing VCL applications, you can use the Mida converter. In the download section of the Embarcadero Developer Network, the MIDA- BASIC version is offered free of charge for download. In the paid Pro version (from approx. 90,-- Euro) also third components (for example TMS components) are converted. In addition, source code is also adapted as far as possible ( Note: In my book for development with Delphi XE7, there was a detailed section on the use of the Mida Converter. For reasons of space and to avoid repetitions, I have removed it for this book, but if necessary, my book for XE7 with the corresponding content for a small amount of Euro is available at Amazon as an e-book.

18 Section 2: New FireMonkey project Of course, it comes to the question of how and when to go into the individual differences between the VCL and FireMonkey. The best way is probably to simply describe the usual steps of program development and emphasize the differences between the common VCL components and the FireMonkey components at the relevant points. FireMonkey desktop application (Multi Device Application) As with any Windows project, you start developing a FireMonkey program to run both on Windows, Mac or Linux under the "File" menu with the command "New Multi-Device Application" or very comfortable directly over the start page: There will be shown a templates dialog, which allows you to generate either an "Blank Application", a "3D application" or an application that already has certain controls in the form:

19 Normally you choose the "Blank Application" when no special 3D-functionality is needed. The other templates would be used rather for mobile applications (i.e. ios and Android). But we want to develop a normal desktop application here, so please select the "Blank Application". Then click OK. Result: The "Target Platforms" on the right side of the node are by default collapsed. Being unfolded, it looks like this:

20 The 32-bit Windows platform is enabled by default. If you want to compile the program now, you will get a running 32-bit Windows program. Delphi has also automatically added a MAC OS platform as well as the mobile platforms ios and Android (but you can ignore the mobile platforms if you don't need it). You can simply select one of the listed target platforms by double clicking and then compile it. And you will have then a corresponding target platform - application. The program will be able actually to run on a MAC or a mobile device, but you still have to set up the environment according to Delphi. It will be described later in this book how to do this for the MAC and also for Linux. Without the additional "FmxLinux" framework, you can not add a Linux platform for a desktop application. If you had created a console application, you could also create an application for Linux, as described in Chapter 5 below. Using the Multi Device Designer (Fire UI) With the Multi-Device-Designer you can get started to add components, set their properties and write event handlers to interact with the user. If you want to develop a cross-platform project, it is generally recommended to add at the very beginning a view for the MAC OS Platform so that you can also compile the MAC-version from time to time and see how it works.

21 However, you should work as much as possible with the view "Master" and only use the other views to make specific settings for the relevant operating system. With the drop-down list on the left side, you can also use the Master View with different styles. In the various created views (OS X, Windows, etc.) you can add components and change their properties, but not delete them. If you want to remove a component, you have to activate the master view and then remove it. Consequently, it is then removed from the other views. The same procedure can be applied to changing the name of a component: Here you can - because the name must be unique - change it only in the Master View. The use of the Multi Device Designer make it much easier to develop crosscompiling applications. For example, the buttons in dialog boxes are located on the left side of the bottom on Windows, and on right side of the bottom under the MAC OS (and Linux). Also, buttons under the MAC OS normally do not have graphics. Here is the view of a dialog from my accounting program that is available for Windows, the MAC OS X and now also for Linux (with the help of the FMXLinux):

22 At the bottom left corner are the buttons with the images. Now have a look at the MAC OS X view: Here, the buttons are moved to the right side and the images in the Object- Inspector are set to visible = false. The checkbox has been moved to the left side. The advantage is that you can use the designer here and do not have to make any programmatic changes for the dialog at runtime. In the past, that was usual and a rather time-consuming working-method. Form inheritance with the Multi Device Designer Also, it is a space-saving method because Delphi creates for each view a separate form and only this is included for the correspondent platform. When the

23 files are created, in a file manager it looks like the following: FMandant.fmx is the master form file. This file serves as a master for the respective generated platform. If we have only this master form and want to create a program for the MAC OS X, we can use this master form only. Here we want to create a Windows program and also a version for the MAC OS X. Therefore we have chosen here "OS X Desktop" in the right drop-down list so that Delphi will create a form for this platform. This is the file "FMandant.Macintosh.fmx". The specific platform forms work on the principle of form inheritance (similar to the "TFrame"). When we open the MAC form in a text editor, it looks like this: While the form master-file consists of 250 lines, the derived MAC form-file has only 42 lines. The reason is that only the changes in relation to the recognized master form will be saved here. The button is now on the right side instead of the left. Therefore it has a different horizontal position and this value (in green here) will be detected. The image symbol in the button should be visible under Windows, but not under the MAC OS X, which is also noted accordingly (blue

24 background). So you can simply modify for a particular platform the position, the color, the size or other contents (e.g. text of labels, buttons). Reverting to inherited settings If you have made changes of a control on a different platform view, you can individually or completely reverse the settings to the values in the master view. Example: The button on the MAC view has been moved to the right side and the text was changed to "MAC". If you want to restore all settings of the buttons back to the initial state, click on the button with the right mouse and select the command "Revert to Inherited": The button is then in the MAC view again on the left side and has again the caption "Button1". If you want, for example, only to restore the original text of the button, click once on the button with the left mouse button to select it. Then, in the Object Inspector, right-click on the word "Text" (on the left side and not in the edit box) and select the command "Revert to inherited".

25 The button stays on the right, but his label was changed from "MAC" to "Button1". So it is possible to bring back only individual properties to the initial state, if necessary. Creating a Platform-specific event handler with the Multi-Device Designer However, the Multi-Device Designer offers a further simplification: Until now, you have the source code in an OnClick event and usually edit it in a event procedure to serve different platforms. Normally you use the IFDEF switch to make the source code compilable for either Windows or the Mac. Even it might actually be the right way, if you have only a few different platform-specific statements in the code. But if the code is very different for each platform, then you have a lot of text in the event handler, which can become unmanageable. It is then possible here to create directly a separate event handler for the MAC platform. So if you have created an OnClick event already in the master, go to the View "MAC OS Desktop". Then select the button and add in the OnClick event simply the words "Mac" as viewable in the image above, then press the key "Enter". Delphi will create a new empty event handler immediately, so that you can fill it with specific source code for the MAC. Small drawback: If the source code contains platform-specific calls, you still have to work with IFDEF, however. But that is much easier now, because you can surround the whole inner frame of the procedure with {$ IFDEF MACOS}... {$ ENDIF}.

26 In general, it is always a matter of the case which approach is the better. There is another innovation (since XE7): Among a number of components, you can select initial settings for certain properties - e.g. the property "PlatformDefault" instead of "Top" or "Bottom" for the TTabPosition in a TabControl. Even if you have only one Master View and do not generate platform-specific views, everything would be on its proper place on all platforms because of the "Platform Default". The functionality mentioned in this example is yet more relevant for ios and Android, because the tabs there should be at the bottom or at the top.

27 Section 3: A first FMX-program (analog clock) Here we want to start with a simple program, which demonstrates at the same time that you can write a full-fledged program with a very few lines of code. This is an analog clock, which will look like this: One could program the app even with only 3 lines of code (therefore the title of the program window). On YouTube you can see this (in German language): We will need here some more lines, but with that we can reduce design work, and we can learn about using style names and simply copying existing FireMonkey objects. Here now step by step: 1. Create a new FireMonkey Multi-Device-Application. 2. Drag and Drop a TCircle-component into the form and set the values for width and height each time to 400 Pixel. Set the property "Fill", "Color" to "White".

28 3. Insert a TLayout-component into the TCircle-component and set the height to 400 and the width to 50 Pixels. For "Align" you select "center". Name the property "StyleName" to "clocknumber". 4. Insert a TText-component into the TLayout-component and set the value for "Text" to "12", under "Textsettings" you select "Bold" and for the size of the text you set 24 points. The preliminary result looks like this: The structure list looks like this: If it looks different on your PC, you can move the elements by drag and drop to the right position. We could go on and copy this TLayout ("LayoutZiffer") 11 times and increase the value for RotationAngle each time by 30 degrees and reduce the value for "RotationAngle" for the TText-Element by 30 degrees (like I have demonstrated it in the mentioned video above). But instead of this we reach this with a few lines of code: 5. Place the following text into the OnCreate-event of the form: procedure TForm24.FormCreate(Sender: TObject); var L: Integer; LA : TLayout; T: TText; begin for L := 1 to 11 do begin // create a copy of the layouts, with child-objects included LA := TLayout (circle1.findstyleresource ('clocknumber', true)); if LA <> NIL then begin LA.Parent := circle1;

29 LA.RotationAngle := L * 30; // We have only one child, the TText-component T := TText (LA.Children[0]); if T <> NIL then begin T.Text := L.ToString; T.RotationAngle := (L*30) * -1; This line here is very important: LA := TLayout (circle1.findstyleresource('clocknumber', true)); Here we get as function result the layout which has the stylename "clocknumber". This is the name that we have set before under "StyleName" of the TLayout-component. The second parameter of the function call determines whether we will get back a link to the original ("False") or if there will be created a copy of the object and we receive a link to that copy (=True). We make the call with "True", so we will get as result a link to the new created copy of the object. In comparison to the original the copy does not have a parent yet, so we have to assign one: LA.Parent := circle1. After that, we assign the needed value for "RotationAngle" to the new created TLayout. But how access the TText-element? We don't have to create it manually, because it was a child-element of the original TLayout. And by creating a copy of the TLayout it will create also all the included child-objects. Because the layout had only one element, we can access it with T := TText (LA.Children[0]); and can make the needed assignments. When we start the program, it looks like this at runtime:

30 So you can see immediately how useful the property "RotationAngle" is. 6. Now we insert 3 TRoundRects so that they are standing vertical and the end is exactly centered. a. Name the first RoundRect "rrhour" and enter the following values: Position.x: 191; Position.y: 94; Height: 110; Width: 18; b. Name the second RoundRect "rrmin" and enter the following values: Position.x: 193; Position.y: 55; Height: 151; Width: 14; c. At the end you name the third RoundRect "rrsec" and enter the following: Position.x: 196; Position.y: 40; Height: 164; Width: 8; For the second hand you choose for "Fill", "Color" the value "red", for the other RoundRects "Black". Also, make sure that the RoundRects are within the circle and that the minute hand is above the hour hand, and the second hand over the minute hand (if necessary, go to the Delphi edit menu and choose "Bring to Front" to change the z-order). 7. For each of the RoundRects you enter the values:

31 RotationCenter.x: 0,5; RotationCenter.y: 1; 8. Finally, add another circle within the circle (color "black") and set the following values: Position.x: 183; Position.y: 183; Height: 34; Width: 34; In the structure list it looks like this: And this is the form-view: 9. Now add a TTimer component (interval = 1000 and Enabled = True) and enter the following code in the OnTimer event: procedure TForm24.Timer1Timer(Sender: TObject); begin rrhour.rotationangle := HourOf(Now) + MinuteOf(Now)/ 2; rrmin.rotationangle := 6 * MinuteOf(Now); rrsec.rotationangle := 6 * SecondOf(Now);

32 Depending on the value for hour, minute or second, the degree value for the component is calculated here. Now the program is finished, you can run it and look at the result. When you run the application on the Mac, the result looks like this: Even when this book is not about mobile programming: if you select "Android" as Target Platform in the Project-Manager and run the app on a via USB connected Android-device, it runs perfect there: Note: To have the clock always to be displayed centered in the form, it is necessary to insert another TLayout into the form. Then you have to align the

33 TCircle to this layout centered (without using the "Align" property) and then set the layout via "Align" to "Center". Here you can download the demo:

34 Section 4: Selected FireMonkey components Based on the individual components and features that you normally use here, let s look into the individual components one by one. TButton (with Trimming) Unfortunately, the FireMonkey TButton has not so many skills, such as this one from the VCL who has gained enormous possibilities in the last few years. But there is something that the VCL button does not have: the property "Trimming", with which you can specify how to handle the displaying of the text if it is too long to display. The default setting is now "ttcharacter". When the text is too long it will be displayed with a letter and 3 points between the outer button border. For example in the text "Repetition" like "Repet...". If you select "ttnone", it behaves as described in the VCL, which means the text is displayed until the border of the button, then cut off. With "ttword", if words are available, the border is set as full word-border. So "Print and Close" would be shortened to "Print and..." when the word "Close" does not fit in the display area of the button. Finally, a TButton can have also a constantly pressed-down status. You can do this by setting the property "IsPressed". At the same time the property "StayPressed" must be enabled. Since Delphi 10.1 Berlin there is also the property "Hint", which is activated by default via "ShowHint". TEdit (without PasswordChar) If an edit-field does not display its contents, you will not reach this as in the VCL with Edit.passwordchar: = '#';

35 but with Edit.password: = True; New since XE7: There is a new feature "ControlType", which is set by default to "Styled". If you set this to "Platform", the native element is used on the platform in your form - currently only on ios and Windows. This can be an advantage e.g. when using a screen reader. Or just when you want to get a 100% platform appearance. If you choose the option, it shows this control changes already at the design time: In addition to the TEdit, the "ControlType" property is also available for the TMemo or the TCalendar control (the latter only for ios). I assume that further controls will be provided with this property in future. Therefore, if you use ios and Android next to the MAC OS platform, this maybe an important information. TExpander You can compare the TExpander component with the TCategoryPanel from the VCL. Here too, you can insert different components into the expander and open or close the component by setting "IsExpanded". TForm (furthermore with caption) While actually all FireMonkey components are not using the "caption" but the "Text" property, the TForm goes on having the property "caption". For FireMonkey forms there is (currently) no "KeyPreview" property as in the VCL form. However, the TForm can still get the FormKeyDown-info even if another control has the focus. If you write a program for which it is important to have a central location where the keyboard input will be checked, you could use the KeyEvent routine of the focused control and then forward it to the form. With the property "FullScreen" you can let the form start directly in full screen mode. This property should not be confused with "WindowState" where you can, as usual, bring the window to the maximum size of the free desktop area

36 (wsmaximize) like under Windows. With the "ShowFullScreenIcon" option, you can activate the full screen icon on the MAC (it has no effect under Windows because there is no full screen icon for the window area). At runtime you can switch between the two modes - both under Windows and the MAC OS X - with "FullScreen: = True" or "FullScreen: = false". TFrame Since XE 4 frames are available, it basically works like in Windows. Under "File", "New", "Other" menu, you can first create a TFrame. Then you can click on the frame icon in the component palette and attach to the form a region in which the frame is to be inserted. This will open a dialog where you can select one of the available frames (if you have not done so before, you have to add an existing frame to the project). TPanel (no caption or text-property, align with qualifier) A speciality has the component "TPanel" which has neither the property "Caption" nor the property "Text". To achieve the results known under Windows, you have to paste a TLabel component into it. If you want to align a TPanel object at runtime, it is not enough (as in the VCL form), to set the align-property for example to "alclient". Rather, you have to use a qualifier, the term "TAlignLayout", before that. Example: Panel.Align: = TAlignLayout.alClient; TRectangle Works similar to a TPanel, but you have to use the Fill property to apply a background color and use the Stroke property to specify a particular type of border. TCheckbox, TRadioButton (IsChecked) When using the TCheckbox- component or the TRadioButton, you do not even need to search for the property "Checked", but just for "IsChecked" instead. Like the (newer) VCL components, also the FireMonkey components with text elements have the property "WordWrap", which is actually quite useful. Like all FireMonkey components, the discussed controls here, has several features to represent its appearance ("Styles", e.g. "StyledSettings", "StyleLookup" and "StyleName", but more later).

37 TGroupBox with TRadioButtons In the VCL, you know the TRadioGroup component, where you can use the "RadioGroup.Itemindex" property to determine the activated radio button. This component does not exist under FMX, but you can use the TGroupBox and place the desired TRadioButtons there. In order for the RadioButtons to be grouped, you must assign a uniform name for each RadioButton within the GroupBox to the "GroupName" property: TSwitch (alternative to the TCheckbox) This component has no equivalent in the VCL. Under FireMonkey, you can use the TSwitch as an alternative to TCheckBox to represent an ON or OFF state. These switches can be found very often in mobile applications, but also in desktop applications now. The component looks like this: TImage (WrapMode for display-modi) With the VCL TImage component, you can use the property "Picture" to load an image. You can influence the way to displaying the picture with the properties "Stretch" and "Proportional". Under FireMonkey, there is also a TImage component. Here, you can use the property "MultiResBitmap" to load the image into the component: This means, you can save as many bitmaps as you need for several resolutions to

38 use. If you call the wizard for editing here, you will get the following dialog: Here you can add individual bitmaps by clicking on the first icon on left side at top. Then you can click on the open icon in the text input line to select an imagefile. By default, the preview will not be displayed on the right side of the dialog. This can be enabled by clicking on the magnifying icon in the toolbar. Note: If you click on the green check arrow, a query will arise, asking whether the information available at design time should be deleted. If you confirm this with "Yes", the name of the source directory of the bitmaps will no longer be displayed here. As long as you still need this information, you should close the dialog with the red close button. At runtime, you will access the individual bitmaps via the items property, e.g. as follows: MyBitmap.assign (Image1.MultiResBitmap.Items [0].bitmap); It is not mandatory to save Bitmaps with various resolutions in this component. You can also save different pictures with same resolution, and in fact, achieve a replacement for the VCL ImageList. However, you cannot enter the same scale value two times. It is convenient that you can drag from Windows Explorer or any other file manager files directly into this image editor. The property "WrapMode" can be used to influence the type of presentation. The following modes are available here:

39 WrapMode: iwfit (Default) - adjusts the image to the square of the component where the image proportions (the ratio between the width and height) are maintained. iworiginal Displays the image with the original dimensions. iwstretch Enlarges the image so that it fills the entire rectangle of the component iwtile Tiles the image so that it fills the whole rectangle of the component. iwcenter Center the image horizontally and vertically in the middle of the component iwplace Fit the image to the TImage rectangle. If the width or height of the image is larger than the corresponding dimension of the TImage rectangle, the image will be scaled to fit the TImage rectangle while maintaining the image proportions (the width to height ratio). The resulting image is set to the center of the TImage rectangle. Place only scales images down and never enlarges them. TImageControl (automatic scaling) A graphic loaded by using the property "bitmap" is scaled automatically. When you click at runtime on the displayed image, a file-open dialog will be shown There you can load an image into the component. If this default behavior is not wanted the TImageControl, you can avoid this with the following assignment: Imagecontrol1.EnableOpenDialog: = false; TImageViewer (pictures scaled by user) The TImageViewer is a very interesting component. Again, you load the graphics with the property "bitmap" into the component. By default, the properties "MouseScaling" and "MouseTracking" are activated here. As a result, the user can scale the size of the graphic with the mouse wheel, when the mouse is over the displayed element. If you want to disable this behavior, you must disable the last-mentioned properties. TImageViewer (to use with the LiveBindings-Designer) The TImageViewer is ideal for producing a dynamic link to another component, by using the so-called "live bindings". Let's see how it works with the track bar component here:

40 In the Object Inspector, we have clicked on "Bind visually" in the property "LiveBindings". This will automatically show the "LiveBindings-Designer". You can then use the property "BitmapScale" from the "ImageViewer1" to connect it with the "Value" property from the "Trackbar1" component. Just click on the 3 dots on the ImageViewer1 element, it will show the dialog "Bindable Members". Then select the property "BitmapScale" and confirm with "OK": Then click on the "Value" at the "Trackbar1" with the mouse and drag it onto the "BitmapScale" of "ImageViewer1" and then release the mouse button.

41 Result: If you do this for the first time, you can also use the "LiveBindings-Expert". To do this, click on the item "ImageViewer1" in the LiveBindings designer. Then click on the icon with the magic wand. This opens a dialog where you can specify the settings: Select "Link a component property with a control," and then click on "Next". In the drop-down list select the component "ImageViewer1" and then "BitmapScale" as property: Then click on "Next" and select on the next page the control "Trackbar1". Then click on "Finish".

42 In the designer you can see now, the property "BitmapScale" from the "ImageViewer1" is linked to the "Value" property of "Trackbar1". The property "BitmapScale" with value of 1 stands for 100% image size. So set the property "Max" of the "Trackbar1" component also to "1". If you want allow magnifications, set it to e.g. 2 or 3. At runtime, you can change the display size of the graphic by using the slider. It's an easy job which doesn't need to create a single line of source code for it. Below is the runtime result: TLabel (New property FontColor)

43 If you wanted to change the color of a TLabel, for example, in the first version of FireMonkey, you had to create a custom style and then set the property "Fill" of the text element with the desired color. From FireMonkey 2 on, this is much easier. Just use the property in the Object Inspector "TextSettings" and then "FontColor" and select the desired color. Note: The selection in FontColor only works when FontColor is disabled in the "StyledSettings" options: I am not going to discuss whether this mixing of the various settings is useful or not. Anyway, you should know this, otherwise you may search long for the answer why the color you have chosen in "FontColor" is not displayed. The property "StyledSettings" refers to the current style. This can be the default style and, however, can also be a user-defined style. The settings of the style override any other settings when it is enabled here in StyledSettings. TPathLabel This component (there is nothing comparable under the VCL) does not display text, but "path data", i.e. vector data, similar to the TPath component. TPath This component also displays vector data, but it has the additional "Fill" property, which means that the filled surfaces can have a (uniform) color background.

44 TImageList The extremely useful TImageList, which serves as a container for graphics and can be edited via a dialog at design time, has been available also for FireMonkey since XE8. Compared to the VCL-TImageList, the FMX version is significantly more powerful. Here is a screenshot of the dialog for adding and editing the TImageList: The "Sources of Images" are displayed on the left. These can be accessed at runtime via "Imagelist1.source". Example: procedure TForm27.Grid1GetValue(Sender: TObject; const ACol, ARow: Integer; var Value: TValue); var SizeF: TSizeF; begin SizeF.cx := 16; SizeF.cy := 16; case ACol of 0: if ImageList1.BitmapExists (ARow) then begin Value := ImageList1.Bitmap (SizeF, ARow); 1: Value := ARow.ToString; The result looks like this: Design-Time:

45 Run-Time: You can also change the ImageList at runtime, e.g. adding a bitmap. Here is a demo. Note that you have to specify the properties for the "source" and for the "destination" as well: procedure AddImageToImgList (ImageList1: TImageList; AFile: string); var bm : TBitmap; Asource: TCustomSourceItem; cd, ditem: TCustomDestinationItem; item: TCustombitmapItem; Layer: TLayer; sizew, sizeh: Integer; begin if FileExists (AFile) then begin ImageList1.BeginUpdate; bm := Tbitmap.Create; bm.loadfromfile(afile); sizew := bm.width; sizeh := bm.height; ASource := ImageList1.Source.Add; Asource.Name := ChangeFileExt (ExtractFileName (AFile), ''); Item := ASource.MultiResBitmap.Add; if sizew <> 16 then begin

46 item.multiresbitmap.width := sizew; item.multiresbitmap.height := sizeh; item.bitmap.assign(bm); bm.free; cd:=imagelist1.destination.add; Layer := cd.layers.add; Layer.Name := ASource.Name; if sizew <> 16 then begin Layer.SourceRect.Right := Sizew; Layer.SourceRect.Bottom := sizeh; ImageList1.EndUpdate; The TImageList is also important if you want to ensure that your program displays an image with a higher resolution at higher screen resolutions. You can store multiple resolutions for each (MultiRes-) bitmap, which are automatically used by FMX for the correct resolution. A simple double-click on the icon in the middle:

47 opens the MultiResBitmap dialog directly, or you can open the MultiResBitmap dialog by double-clicking on list on the left-hand side: Here are the values for "scaling" important, for the selection of the right icons at runtime. TListBox (not TCheckListbox, but ShowCheckboxes) Don't waste your time to search a TCheckListBox as there is not such a component for FireMonkey. If you want to display a TListBox with checkboxes, select instead the "ShowCheckBoxes" option. Quite interesting is the property "ListStyle". With that you can display the entries in the list box next to each other (lshorizontal). Here's an example: Although the listbox works in general like the VCL component (e.g. Items.LoadfromFile, etc.), it is to distinguish whether you are working at design time or run time with "Items" or "ListItems":

48 In the listbox above on the left side, the entries were added by using the "Strings" property of the listbox. In the listbox on the right I have right-clicked with the mouse and then selected the command "Add ListBoxItem". As you can see in the structure-overview, only the second listbox has individual entries for each "ListBoxItems". So only in the second listbox you can select the individual ListBoxItems by mouse-click and make the appropriate changes to the settings in the Objectinspector. Warning: if you now edit the entries in the second listbox by the property "Strings" and confirm the changes, all ListBoxItems would be converted to normal strings and all previous settings to the individual ListBoxItems would be lost. Therefore you have to be careful of how to process it here. Here is an example of how to access the items. At design time: At runtime, you can address the individual items of a TListBox both on the property "ltems" (= list of strings) and on the properties of the "ListItems" (list

49 of TListboxItems). See the example source code with this result: procedure TForm19.FormCreate(Sender: TObject); begin Listbox1.Items[0] := 'Text set via "Items"-property'; Listbox1.ListItems[1].Text := 'Text set via "ListItems"'; Listbox2.Items[1] := 'Text set with "Items"-property'; To test, whether in a ListBoxItem the property "IsChecked" is set, do it like this: if Listbox1.items[0].isChecked then... Listbox1.items[0].isChecked := True; Enhancement of the Listbox-Items Beginning with Delphi XE4: If you right-click with the mouse on the listbox, you can not add only simple text entries. As you can see here in the pop-up menu, you have the choice between several entries:

50 With a TListboxGroupHeader, you can use the subheadings in the listbox. The TSearchBox is very useful. When you enter text there, the ListboxItems will be filtered and shows only the matching entries. For example, if the list box offer quite a lot of options, the user can enter a keyword and immediately receives the appropriate setting option. That is something comfortable, that the VCL listbox does not offer! Here is a list box with a group header and a SearchBox: And this is the listbox after the user has input some text into the SearchBox: If you click in the SearchBox on the ClearEdit button, it clears the contents of the text SearchBox. As the filtering happens all automatically, you need not write a single line of source code! No OwnerDraw for listboxes Since there is no "OnDrawItem" event for the listbox, you have to work with the appropriate settings for the ListBoxItem so as to get the different representation (but note: There are existing events like "OnPaint" and "OnPainting" for the ListBox and for every ListBoxItem, which you can use in special cases).

51 Most of the time, it is sufficient to get along with the pre-installed properties of the TListBoxItem, since it offers, in addition to the text property, a number of other uses: Under Bitmap, you can assign a bitmap at design time or at runtime. Starting with Delphi XE8, the ListBox has an entry "Images", where you can create a link to a TImageList (which only exists since XE8). Accordingly, each LitboxItem has an entry "ImageIndex", where you can also create a reference to an image from the ImageList at design time or at runtime. The "Detail" property stands for another text entry, which can be displayed within the TListBox item at different locations, depending on whether you choose "leftdetail" or "rightdetail" for the "itemstyle". Under Accessory you can choose the following: If the text from the "Detail" property is to be displayed, select "adetail" for "Accessory". And as "ItemStyle", select a style that contains the term "detail":

52 In this way you can solve most standard tasks with the integrated skills. Under the VCL you have to draw the desired output yourself by "Ownerdraw". Here is a step by step example of how to output text in a listbox with different colors, with an icon and detail information: This is the finished program. When you enter text in the search box, the contents of the listbox are filtered out accordingly. While this functionality is set up very quickly under FMX, you would have a lot of effort under the VCL to reach the same result.

53 1. Create a new multi-device project. 2. Add a TListox, name it "lbevents", and select "listboxitemrightdetail" for "Itemstyle" (under DefaultItemStyles). 3. Add a TImageList and add three icons: 4. Set the "Images" value of the listbox to "ImageList1". 5. Add 3 buttons, and assign the text property "Add Info", "Add Warning" and "Add Error". 6. Add a search box to the listbox by right-clicking: Your form looks now like this:

54 7. Create the following procedure, and for the OnClick events of the buttons, the following events: procedure AddInfoItem(lb: TListBox; imgidx: Integer; txt: string; AColor: TAlphaColor; ADetail: string = '-'); var lbi: TListBoxItem; begin lbi := TListBoxItem.Create(lb); //lbi.stylelookup := 'ListBoxItem1Style1'; lbi.itemdata.text := txt; lbi.itemdata.detail := Adetail; lbi.imageindex := imgidx; lbi.styledsettings := lbi.styledsettings - [TStyledSetting.Fontcolor]; lbi.textsettings.fontcolor := AColor; lb.addobject(lbi); procedure TForm24.Button1Click(Sender: TObject); begin AddInfoItem (lbevents, 0, 'Information here...', TAlphaColorrec.Black); procedure TForm24.Button2Click(Sender: TObject); begin AddInfoItem (lbevents, 1, 'Warning here...', TAlphaColorrec.blue, 'Battery is at 5%!'); procedure TForm24.Button3Click(Sender: TObject);

55 begin AddInfoItem (lbevents, 2, 'Error here...', TAlphaColorrec.red, 'Disk is damaged!!'); This completes the program and you can run it. Two notes about the "AddInfoItem" procedure: 1. To make it possible that the text can be displayed in color, the "FontColor" property must be removed from the StyledSettings. 2. To the commented out line: You could also arrange the existing elements of the ListboxItem differently for the display. For example, let the detail text under the normal text and the text a little closer to the icon. To do so: a) Change the value for "ItemHeight" to 40. b) Temporarily add a TListboxItem to the listbox, right-click and select "Add custom style". c) In the structure list under "ListBoxItemStyle1", set the value for Height to 40 and move the "detail" element to the first layout, set Align to "Bottom" and choose for Height 16: If you enable the commented out line above, and run the program again, the result looks like this:

56 You can download the demo here: But you are not at the end of the possibilities. You can also add additional text, images, or other elements to the "Style" for the ListboxItem. To do this, you can look at an example provided by Delphi: "CustomListbox", which you usually find here: C:\Users\Ihr AnwenderName\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\Multi-Device Samples\User Interface\CustomListBox The compiled example looks like this: All Components (except the form) While the TForm contains properties such as "Left" and "Top", all other components does not have that. Here you can use the property "Position" with the X and Y values for the left and top position. It should also be noted that none of them are integer values but of the type "extended".

57 Several Components (Properties with additional type-qualifying) In many FMX components, you can use the properties like in the VCL components. In a TMemo you can use the property "Align" to assign the value "alclient". However, at runtime you must provide additional type qualifiers. Not: memo1.align := alclient; But: memo1.align := TAlignLayout.alClient; Even not: memo1.fontcolor := clred; But: memo1.fontcolor := TAlphaColors.Red; The well-known "clcolorname" of the VLC components works here under FireMonkey always without "cl", but with "TAlphaColors" before it. So if you're going to make common assignments and the program does not accept that, try to figure out whether an additional type qualifier is required. TAlphaColors itself is declared in the unit "System.UITypes": Type TAlphaColors = TAlphaColorRec; But once you know this, it is OK. However, there's also a trick to bypass the use of this qualifier. Simply link the unit "System.UIConsts", then you can use color values such as "clared," "clablack". Uses System.UIConsts;... memo1.fontcolor := clared; // Alternative: TMenuItem) Since Delphi-XE8, in the TMenuItem the "Bitmap" property has the "ImageIndex" property, so you can assign a symbol to a linked TImageList. If you create a Cross-Platform application here, you should consider, that other

58 platforms then windows normally doesn't use bitmaps in menus (MAC and Linux). So you can add an "OSX Desktop" view with the Multi-Device Designer and remove the "Items" item for the menu in this view. Or you remove the icons from the menu at runtime. It should also be noted, that in the FireMonkey component the setting "IsChecked" is used instead of "Checked". TMainMenu (Handling MAC Menus) If you compile your program, you have usually the "File" menu in the Windows version. In the compiled version for the MAC the name of the program (that is the ".exe file" - without extension) is set from the first menu-name. In this menu we have usually only commands to exit the program or a command to call a settings dialog or a command "Information about...". So it is recommended to create another menu with that name as the first entry: In the Windows version you have to let the "TEditor" invisible. In the MAC version, you make it visible and hide the "Exit TEditor" from the "File" menu. Here is the implementation in the source code: procedure TF_Main.FormCreate(Sender: TObject); begin {$IFDEF MACOS} mteditor.visible := True; mfileexit.visible := false; // from Menu File {$ENDIF} //...

59 And so it looks like the following in the Mac: You can use this solution if you have only one master view and no specific view for the MAC platform. However, if you have a specific form for the MAC, you can edit the properties of the menu over the Object Inspector. In the "OS X Desktop" view you set the text for the "TEditor"-menu to visible and hide the "Exit"-entry under file-menu. The name of the first visible menu entry is always replaced by the program name (executable) under Mac OS. Therefore, you should choose the project name of the application carefully. TMemo (CaretPosition, no Modified, FindNext-replacement) Under Windows, you can determine the current row and column in the memo as follows: Line: = SendMessage (memo.handle, EM_LINEFROMCHAR, Memo.SelStart, 0); column: = Memo.SelStart - SendMessage (memo.handle, EM_LINEINDEX, line, 0); Under FireMonkey, it works like that (use property "caret position"): line := Memo.CaretPosition.Line +1; column: = Memo.CaretPosition.Pos+1; The property of the VCL component "Modified" does not exist under FireMonkey. You must, instead, manage it by yourself under the event "OnChange" or "OnChangeTracking". Here you can set a variable (e.g. the "Tag" variable of the TMemo), which records whether the memo has been altered or not. You can reset it later when you have saved the contents of the memo into a file. Clipboard.HasFormat(CF_Text) -replacement

60 Under the VCL there is the "Clipboard", but not under FireMonkey. For the FireMonkey memo component we have functions such as "Memo.CopyToClipboard" or "Memo.CutToClipBoard" and "Memo.PasteFromClipboard". But how to determine if the clipboard contains text (for example, to make a button enabled)? Here you have to use a PlatformService. Example (unit "FMX.Platform" is required): procedure TF_Main.Timer1Timer(Sender: TObject); var s: String; ClipService: IFMXClipboardService; begin try if TPlatformServices.Current. SupportsPlatformService(IFMXClipboardService, IInterface(ClipService)) then begin try s := ClipService.GetClipboard.ToString; bnpaste.enabled := (s <> '') and (s <> '(empty)'); finally finally Spellchecking A whole new possibility arises from XE5 on, with the ability to make a spellcheck for the text entered. And it works with a service that is automatically available under the MAC. You enable or disable the spell-checker with the Boolean variable "CheckSpelling" (either in the Objectinspector or at runtime). For the spell checking, a platform service will be used. It could be a good idea to check first whether the service for the Platform currently used is available. To query this, you need to include the units "FMX.Platform" and "FMX.SpellChecker". The query looks like this: IF TPlatformServices.Current.SupportsPlatformService(IFMXSpellCheckerService) then begin

61 memo1.checkspelling := True; For Windows, no spell checker service is available. But in principle, it should not be difficult to implement an own one. As a template, you can take the implementation for the MAC platform and rewrite it accordingly for Windows. FindNext-Replacement Unfortunately there is not the most useful function "Memo.FindNext (Memo.text, StartPos, EndPos, SearchOptions)" for the FireMonkey Memo component available as in the VCL. Even among the standard actions, there is no corresponding action. So you have to use your own solution. Subsequently, I demonstrate a simple approach which I have used in my program "TEditor" for the MAC and Windows. Here is a simplified version of the TEditor program for the FindReplaceDemo: When you click on the search icon (magnifying glass), the following routine will be executed: procedure TF_MainFindReplace.SearchEditButton1Click(Sender: TObject); var P,L: Integer; cp: TCaretPosition;

62 begin for L := 0 to Memo1.lines.count -1 do begin if cbgreat.ischecked then begin P := Pos (edfind.text, Memo1.lines[L]); end else begin P := Pos (ANSIUPPERCASE (edfind.text), ANSIUPPERCASE (Memo1.lines[L])); if P <> 0 then begin cp.line := L; cp.pos := P-1; break; if P <> 0 then begin Memo1.SetFocus; Memo1.CaretPosition := cp; Memo1.SelStart := Memo1.PosToTextPos(cp); // - (cp.line)-1; Memo1.SelLength := Length (edfind.text); if cbreplace.ischecked then begin bnreplace.enabled := True; bnreplaceall.enabled := True; end else begin if cbreplace.ischecked then begin bnreplace.enabled := false; bnreplaceall.enabled := false; This was the function for the first search. If you want to search the next item, you have to start from the current position, behind the selection. The source code for this is as follows: procedure TF_MainFindReplace.bnFindNextClick(Sender: TObject); var P, L: Integer; cp: TCaretPosition; part: String; begin for L := Memo1.CaretPosition.line to Memo1.lines.count -1 do begin if cbgreat.ischecked then begin if L = Memo1.CaretPosition.line then begin P := Instr (Memo1.CaretPosition.pos+Memo1.selLength,

63 Memo1.lines[L], edfind.text); end else begin P := Pos (edfind.text, Memo1.lines[L]); end else begin if L = Memo1.CaretPosition.line then begin P := Instr (Memo1.CaretPosition.pos+Memo1.selLength, ANSIUPPERCASE (Memo1.lines[L]), ANSIUpperCase (edfind.text)); end else begin P := Pos (ANSIUPPERCASE (edfind.text), ANSIUPPERCASE (Memo1.lines[L])); if P <> 0 then begin cp.line := L; cp.pos := P-1; break; if P <> 0 then begin Memo1.CaretPosition := cp; Memo1.SetFocus; Memo1.SelStart := Memo1.PosToTextPos(cp);; Memo1.SelLength := Length (edfind.text); if cbreplace.ischecked then begin bnreplace.enabled := True; bnreplaceall.enabled := True; end else begin if cbreplace.ischecked then begin bnreplace.enabled := false; bnreplaceall.enabled := false; // Note: The example used in the Instr function is a own help function that looks like this: function Instr (AtPos: Integer; S:String; tofind: String): Integer; var R : Integer; begin S := Copy (S, AtPos, (Length(S)-AtPos)+1); R := Pos (tofind, S);

64 if R <> 0 then Result := R + AtPos -1 else Result := 0; If you want to replace the selected text, click on "OK", then the following routine will be executed: procedure TF_MainFindReplace.bnReplaceClick(Sender: TObject); begin if Memo1 <> NIL then begin if Ansiuppercase (Memo1.SelText) = Ansiuppercase (edfind.text) then begin Memo1.DeleteSelection; Memo1.InsertAfter (Memo1.CaretPosition, edreplace.text, [TInsertOption.ioSelected]); Here is once again a typical cliff. We have to use "TInsertOption" as a qualifier here. You can download the simplified FindReplaceDemo from my homepage. It contains also the source code for the click on the button "Replace All". In this procedure you will find three positions, where "Application.ProcessMessages" is executed. One should always consider this function when any interactions have to take place with the host system, e.g. to set the position of the cursor. Here's the link to download the demos: Of course, it also works on the MAC. By the way, a REDO function (like on VCL) is not available. Printing a TMemo Printing a memo under FireMonkey is unfortunately a bit more complicated. Under the VCL component, functions such as "Canvas.textout (x, y, 'Text')", etc. were available and we have functions that cause an automatic line break for longer texts. Under FireMonkey, you must calculate this by your own.

65 The function to use under FireMonkey is Canvas.Filltext(). It should be noted that the data for the page width and height are different on the MAC by the factor of 10, which is taken into account in the calculation with corresponding IFDEF's. Here is a simple example that works on both on Windows and the MAC (the unit FMX.Printer is required): procedure TF_Main.mPrintClick(Sender: TObject); var r, rpage: TRectF; i: Integer; tf: tfilltextflags; a: TTextalign; T, th: Extended; sl: TStringList; z: Integer; function GetFormattedLines (s: string): TStringList; var x, L, p: Integer; pw: Extended; label StartAgain; begin sl.clear; if S = '' then begin sl.text := #13#10; Result := sl; exit; {$IFDEF Win32 OR Win 64} pw := (rpage.right - rpage.left) - 100; {$ENDIF} {$IFDEF MACOS} pw := (rpage.right - rpage.left) - 1; {$ENDIF} StartAgain: for L := 1 to Length (s) do begin if Printer.Canvas.TextWidth (Copy (S, 1, L)) > pw then begin for P := L Downto 1 do begin

66 if S[P] = ' ' then begin sl.add(copy (S, 1, P-1)); S := Copy (S, P+1, Length (s)); Goto StartAgain; sl.add(copy (S, 1, L-1)); S := Copy (S, L, Length (s)); Goto StartAgain; if S <> '' then begin sl.add(s); Result := sl; begin if ActiveMemo <> NIL then begin if PrintDialog1.Execute then begin tf:= []; a:=ttextalign.taleading; sl:= TStringList.Create; with Printer do begin {$IFDEF Win32 OR Win 64} r := RectF(200,200,(Pagewidth - 200),(PageHeight - 200)); rpage := RectF(200,200,(Pagewidth - 200),(PageHeight - 200)); {$ENDIF} {$IFDEF MACOS} r := RectF(20,20,(Pagewidth - 20),(PageHeight - 20)); rpage := RectF(20,20,(Pagewidth - 20),(PageHeight - 20)); {$ENDIF} BeginDoc; th := canvas.textheight('test'); T := 0; for i := 0 to ActiveMemo.Lines.Count-1 do begin sl := GetFormattedLines (ActiveMemo.Lines.Strings[i]);

67 for z := 0 to sl.count-1 do begin T := T + Th; if T+th+th >= rpage.bottom-rpage.top then begin T := 0; r.top := rpage.top; Printer.NewPage; r.top := r.top+ th; Canvas.FillText(r,sl[z],True,1,tf,a,a); Canvas.Font.Family := ActiveMemo.Font.Family; Printer.ActivePrinter; EndDoc; TDropTarget (how drag & drop works in FireMonkey) Those who have been programming with Windows and the VCL components may know that one had to call the function "DragAcceptFiles" so as to activate drag & drop to take over the file from the Windows Explorer. Then we had to ensure that the message WM_DROPFILES was processed in the form and write an event handler for it. A little bit complicated, I mean. Here we take a look at the provided "ControlsDemo" I mentioned before. Generally, it is thought that one uses the TDropTarget component in its application to where the user can "drag & drop" one or more files (but you can also use normal components on which you can "drag and drop" anything). At runtime, move the rectangle or the circle over the drop target icon and release the mouse button. In the edit box the class name of the dragged element is then displayed as a result.

68 Let's have a look into the DragOver event of the DropTarget: procedure TfrmCtrlsDemo.DropTarget1DragOver(Sender: TObject; const Data: TDragObject; const Point: TPointF; var Operation: TDragOperation); begin Operation := TDragOperation.Link; With that, we tell the program that the drop operation is "allowed". By default, the default value of "Operation" is "None", which means, it is not allowed. In addition "Move" and "Copy" also exists. A special visual feedback you have (under Windows) only when you drag a file from the Explorer over the target: On the MAC, an corresponding icon appears, even when you drag components only inside the form. By the way, the demo works only from XE7 on. In all previous versions of the demo, the property "HitTest" of a parent component was disabled, so that no evaluation of the corresponding mouse actions was processed.

69 When the property "Filter" is empty, all dragged files will be accepted. If you want that only certain file types can be dragged on the drop target, enter an appropriate filter. You then change the settings of the filter to "*.txt" under Windows or the MAC, when only text files shall be allowed for drag & drop actions. To make sure, that the filter works properly, you have to format the string of the filter-object like this: '<first filter name> <first filter value> <second filter name> <second filter value>... <n-th filter name> <n-th filter value>' Example: only ".exe" and "*.txt" are allowed: 'Applications (*.exe) *.EXE Text files (*.txt) *.TXT' The arrow is animated and the symbol "Link" (or "Copy" or "Move") appears, which means the DropTarget will accept the files. Now the question is how to evaluate it when the user released the mouse button. Here an example: procedure TfrmCtrlsDemo.DropTarget1DragDrop(Sender: TObject; const Data: TDragObject; const Point: TPointF); const Data: TDragObject; const Point: TPointF); var I: Integer; begin if Data.Source <> nil then Edit1.Text := Data.Source.ClassName else Edit1.Text := Data.Files[0]; The files, dropped on the target are included in "Data.Files", where "Files" is an array of strings. In the procedure above, I showed you how to get access to it. Of course, it will work also on the MAC: If "Data.Source" is not NIL, it is a component that has been dragged to the target in the program itself. Of course, you can also drag and drop some files on a normal edit - box.

70 Tip12 in chapter 11 tells how to do it. TRichEdit (not available - but possible for replacement via 3rd-party) A TRichEdit component is for FireMonkey not yet available. Thus you have to use a component from third parties. Since the beginning of 2015 there is a very good RichEdit component available from TMS software: TTMSFMXRichEditor: s=fmxricheditor#features For this component is even a spell-checker offered, which is really helpful. TPageControl (not available - but replacement available) Such an extraordinarily useful component under Windows cannot be found in FireMonkey. However, the TTabControl component provides a reasonable compensation (see below). TStringGrid (works different) This component is very often used in VCL programs. Like the FireMonkey listbox also the FireMonkey TStringGrid does not have an OwnerDraw event (but an OnPainting event, which will be introduced in detail later). When you insert a new TStringGrid into the form, you will get this situation: As you can see, the grid element contains no columns. You also will not find a property "Columns" in the Object Inspector.

71 You can add columns, by clicking on the StringGrid-component with the right mouse button. From the context menu, you can select either the entry "Items Editor" or the command "Add TStringColumn". As you can see below, we have added two columns with the entry-editor. You can now click on a "StringColumn" and set different properties, for example, the property "header". The header is actually not the row-number zero of the grid, but a separate element. Keep this in mind, when you convert source-code from VCL to FMX. You may show or hide the header with the property "ShowHeader". The property "RowCount" exists also in the FireMonkey StringGrid. By default, a grid has initially 100 lines. Therefore, the assignments shown here in the "FormCreate"event are working correctly:

72 Assignments made without adding Columns before would not work. The columns can, of course, also be generated at runtime, if necessary. But how can we change the font-settings (e.g. bold or font color)? The StringColumn component has not a font-property, but the StringGrid component has one under the "TextSettings". But all the settings you make here are valid for the whole grid. If you want it to be different for one or several columns or cells, you can use the "OnDrawColumnCell" event. Example: procedure TForm9.StringGrid1DrawColumnCell(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates); var Flags: TFillTextFlags; ar: TRectF; begin Flags := [TFillTextFlag.ftRightToLeft]; canvas.beginscene; ar := bounds; ar.inflate(-1,-1); canvas.clearrect(ar); canvas.font.style := [ TFontStyle.fsBold ]; canvas.fill.color := TAlphaColors.Red;

73 canvas.filltext(bounds, Value.ToString, True, 1, flags, TTextAlign.taTrailing, TTextAlign.taCenter); canvas.endscene; The result looks like this: The text output is in bold and in red. One note: there is a separate event for drawing of the column header: "OnDrawColumnHeader". We have now also "OnDrawColumnCell and" OnDrawColumnBackground " as new events available. You can then draw the text of the column left, right or centered, depending on the program logic. And you can set this by using the different "TTextAlign" parameters, e.g. "TTextAlign.taCenter" for centered text. To distinguish: "OnDrawColumnBackground" is only called if the grid is in edit mode, otherwise the "OnDrawColumnCell" is used for output. If the "DefaultDrawing" setting is activated (default), the grid first draws its content itself. If you disable this option, no output is made (the grid lines are always drawn as long as the "ColLines" or "RowLines" is activated in the options settings). Here, depending on the program logic, you can output the text of the respective column to the right or centered by specifying the TTextAlign parameters (for example, TTextAlign.tacenter). Note: Under Delphi Seattle about 36 events were published for the StringGrid (made visible in the object inspector). Under Delphi Berlin it was only 13, under Delphi Tokyo it is now again 22. Probably it was a bug, which was now

74 repaired. It is important for you to know that, in addition to today's 22 events, other events are available for the grid, but you have to allocate them yourself at runtime. For example, Events such as "OnEnter", "OnExit", or "OnViewPortPositionChanged". There are about 44 "On-Events" for the StringGrid. Simply enter "StringGrid1.On" once in the editor and press the Strg + spacebar to display the available events (of course you must have a StringGrid on the form or declared a corresponding variable). The "OnCreateCustomEditor" event is also worth mentioning (also in relation to the VCL StringGrid). Here you can create your own cell editor or specify it for editing. For example, you could use a TComboEdit, which then offers comfortable options for text selection. Here is a short source code example and the runtime result: procedure TForm1.FormCreate(Sender: TObject); begin StringGrid1.Cells[0,0] := 'Toyota'; procedure TForm1.StringGrid1CreateCustomEditor (Sender: TObject; const Column: TColumn; var Control: TStyledControl); begin Control := TComboEdit.create (self); TComboEdit (Control).Items.Add('Mercedes'); TComboEdit (Control).Items.Add('BMW'); TGrid (Image and other elements in the Grid) What you have done with "OwnerDraw" events in the VCL (String-) Grid component, for example, displaying images or checkboxes, can be de done here easily with the TGrid. Beside TStringColumns, you can also use "TImageColums" or "TCheckColums".

75 Click on the TGrid with the right mouse button and select the required entry: The number of Column types are constantly increasing. While under XE7 it were 8, now under Delphi Tokyo we have 12 types. The special thing with some column types, e.g. "TDateColumn" and "TTimeColumn" is, that special editors are offered (here a TDateEdit and a TTimeEdit). To display text you use the the "GridGetvalue" event. The first picture shows the form at design time and the second at run time: Here you can see the source code being used: procedure TForm2.Grid1GetValue(Sender: TObject; const Col, Row: Integer; var Value: TValue); var acol: TColumn;

76 begin acol := Grid1.ColumnByIndex(Col); if acol = StringColumnText then Value := inttostr (Row+1) else if acol = ImageColumn1 then begin if odd (Row) then Value := Image1.Bitmap else Value := Image2.Bitmap; As far as images are concerned, it is much easier with the "TGlyphColumn". You must assign a TImageList to the StringGrid ("Images" property). And then you can simply assign the desired entry from the imagelist in the "OnGetImageIndex" event. Depending on the program-logic, you can show images, texts or checkboxes. Thus, with the TGrid a very flexible component is provided, which is ultimately much more powerful than the VCL TStringGrid. TStringGrid-alternative (TMSFMXGrid) As a long-time user of the TMS components I am glad to give you an alternative that could make the transition from the VCL StringGrid to a FireMonkey grid more easily: The TMSFMXGrid which, in addition to the usual VCL properties (ColCount, DefaultRowHeight, etc.) has many other skills (such as export the contents to an Excel file). For more info: THeader (not sections, but items) This component also exists for FMX. In the VCL we have sections, here in FireMonkey we have "Items", which are "THeaderItems". THeaderControl (is not available under FireMonkey) This component does not exists under FireMonkey. Use the THeader instead. Since the individual THeader items work as containers, you can easily insert here required elements, such as checkboxes or bitmaps.

77 TProgressBar (not "position" but value) The TProgressBar works in essential things like the VCL component. But in FireMonkey components, you don't use the property "Position", but "Value". The Position property is used with Position.x and Position.y to set the horizontal and vertical offset of the component. TTabControl (no OwnerDraw) This component works similar like the VCL version. You can generate individual TTabItem elements and then insert here your components. Of course you can create TTabItems also at runtime and then paste them into the TTabControl. An "OwnerDraw" property and an "OnDrawTab" event do not exist, but you have an "OnPaint" and an "OnPainting" event, where you can use the canvas to draw text. Beside this, there are the Styles "TabControlStyle" and "TabItemStyle" through which you can make the corresponding optical adjustments via the "OnApplyStyleLookup" event. TTrackbar (helpful property "tracking") The FireMonkey TTrackbar component has, in contrast to the VCL component, the property "Tracking". If you set this to "False", the OnChange event is only triggered when the move of the trackbutton has been completed (the user has released the mouse button). TSpeedButton (without Bitmap) In the VCL-TSpeedButton an image can be assigned with the property "Glyph". This is also possible under FMX, but it is different and more comfortable at the same time, since you can simply select an image via a linked TImageList via "ImageIdex". TStatusbar (a way to compensate the missing "Panels") In the VCL TStatusbar you can display a text either on the property "Panels" or via the "SimpleText" property. In the FireMonkey status bar, there is neither something of this kind nor text property. But you could use the status bar as container and insert Labels. MessageDlg (e.g. not directly usable with mtwarning) With this dialog, there is a problem, if you try to use it like in the VCL.

78 What works here under Windows: if MessageDlg('Info', mtwarning, [mbyes, mbno], 0) = mryes then begin // do something or not does not work with FireMonkey. Here it should look as the following: if MessageDlg('Info', TMsgDlgType.mtWarning, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mryes then begin // do something or not Thus, the qualifiers are required... It has cost me some time to figure out how it works.

79 Section 5: The FireMonkey Style-Designer a) Using the Style Editor Double-click on a possibly existing StyleBook or right-click on a control and select the command "Edit Custom Style" if you only want to change the style for one component or select "Edit Default Style", if you want to change the default style for all components of this type in the current project. You will then see the following screen: In the tree view on the left, you can select the individual styles and assign appropriate values in the Object Inspector. Over the tree view on top, there is a button which allows you to delete layout elements from the tree view.

80 And deleting elements works only with this button. The delete key does not work here. The StyleBook and the styles have a very great importance for the work with FireMonkey. Styles are often used to achieve the same optical results like in the VCL by using the OwnerDraw events. When you have called the style editor under Delphi XE2, the control was then selected in the tree-view and in the middle of the IDE-window the control itself was drawn. Unfortunately that is from XE3 on not the case any more. Now, on the left side, only the tree view is shown and no item is selected. If the structure list is slightly longer, it's not so easy to find the desired item quickly. Many users do not understand at all what they can do at this place. Therefore: first click on the element displayed in the center of the screen, then the element is selected also in the structure view. From Delphi 10 Berlin on, the search is also supported by direct text input. Select the structure list and type the name of the object you are looking for (but there is no edit field, you must type "blind"). Some explanations about the symbols in the style-editor toolbar: Symbol Description Creates a new, empty FireMonkey style. Opens a dialog box where you can select a FireMonkey style to load. RAD Studio provides some FireMonkey styles. You can find them in C:\Program Files (x86)\embarcadero\studio\19.0\redist\styles\fmx. Opens a dialog box where you can

81 select a FireMonkey style to add all of its style objects to your current style. Saves the current FireMonkey style into a.style file. You can use the - and + buttons to adjust the zoom of the object design area. Supported zoom levels are multiples of 100% between 100% and 1000%. Selects a target platform to edit. Opens a dialog box to select a platform to add to the Platform combo box:

82 Removes the currently selected platform from the Platform combo box. Use a transparency grid as background for the object design area. Use a white background for the object design area. Use a black background for the object design area. The arrow head of this button lists style items of the style that do not exist for the selected Platform but are available for other platforms of the current style. Click a style item on the list to add a copy to the current platform of the style. b) Styles in FireMonkey - an overview A "Style" describes a particular type of representation of a control, a form or an entire application. Such styles are also known in the VCL. From XE2 on, in a VCL application, it is able to select an application style for a Windows application (under "Project, Options, Application appearance"). With the following XE versions, the thing has been so far refined on the VCL side, because each control has received the property "StyleElements". This allows you to specify how elements are displayed (client area, borders, fonts) and if the style should be applied or not. A similar property of comparable meaning is also

83 available for a number of components in the "StyledSettings" under FireMonkey. FireMonkey and VCL have so far moved closer by the time. From XE3 on, the Bitmap-Style Designer is available to edit the VCL styles. And you can save these VCL-styles as FireMonkey Styles, too. Let's look, first of all, at the basics of the FireMonkey styles. FireMonkey styles are included with Delphi and shipped as style files. You can find these in Delphi Tokyo e.g. under C:\Program Files (x86)\embarcadero\studio\19.0\redist\styles\fmx These are text-files which you can load into a text-editor. Load it once so that you can get an idea of such a file. In your program, you can load this style files either at design time in a StyleBook component or at run-time. In addition, the standard styles are already integrated in Delphi. Even if you put no StyleBook on your form, there is already a standard style which is always used when you don't load another style. This standard style then ensures that your program appears as a typical Windows program under Windows and as a typical MAC OS X program under the MAC. How does it work now so that a TButton will be drawn with the help of styles and reflect a normal, a focused or pressed state? Well, before I give the answer, let me remark that the high dynamic in the development of the FireMonkey framework is shown here. From XE2 to XE4, there was always another technical solution for that. I'll spare the details and show here only how it proceeds under Delphi 10.2:

84 The background of TButton is defined in "background", where the background is a "TButtonStyleObject". This object contains a reference to a section of a bitmap. If you click on "background", you can find in the Object Inspector the items "NormalLink", "FocusedLink", "HotLink" and "PressedLink" that are all defined as "TBitmapLinks": If you click on such a "TBitmapLink", you will get the following view:

85 Here you can see the settings for "FocusedLink", for the Windows 10 Style selected (box "Links"). Instead of having to enter any values manually, you can simply move the selection frame as required. The Bitmap has been available in Delphi 10 in the resolutions 1, 1.5 and 2 fold (in the physical resolutions 400x600, 600x900 and 800x1200 pixels). Depending on the resolution (DPI) the program runs later, the most suitable resolution available is chosen here. If necessary, however, you can add additional resolutions, simply click on the button with the plus symbol. If you would load the Windows 10 ModernStyle, you would find also a 3-fold

86 resolution. You can also add your own bitmaps to a style and use your own bitmap style. By the way, you can also find a "FocusedLink" for the TSpeedButton, but it has the same source-position as the "NormalLink" because the state "Focused" does not exist for the TSpeedButton. As mentioned earlier, there is no bitmap-link in the styles for XE2. It starts with XE3. This makes it possible to draw the representation of the components more quickly. Because it is easier to use an existing bitmap for the drawing instead of drawing a complicated appearance at run time. The knowledge of the standard styles is important if you want to create a custom style for a component, e.g., for a TButton. The structure of a button style is still different if you are using the supplied FireMonkey styles. If you load here the "Dark Style" into a StyleBook, you will get for the TButton the following structure presented in the tree view: The background consists of a TRectangle that contains two TColorAnimations, a TGlowEffect and a TGlyphStyle. The file contains no style bitmap. As you can see, there are ultimately several ways to define the appearance of a component. In general, it is worth looking once at the basic styles of the individual components in the style-editor, which will increases our understanding of the use of the FireMonkey components. c) How to convert VCL Styles to FireMonkey Styles

87 It's very useful that you can convert VCL Styles into FireMonkey styles, and then use it in FireMonkey applications. Proceed as follows: In Delphi call the command "Bitmap Style Designer" in the "Tools" menu. Then open it, e.g., under C:\Program Files (x86)\embarcadero\studio\19.0\redist\styles\vcl\luna.vsf In the "File" menu call the command "Save As". In the dialog that appears, select the file type "FireMonkey Style": Save the file to a folder of your choice (preferably in the one that will be not deleted when you uninstall Delphi). In a FireMonkey project, you can then load and use this style file in a style-book. It will look like this: d) Using FireMonkey Styles How can your application get the style you want? There are several possibilities. Either you load one of the supplied style-files at design time in a StyleBook component that you put on your form (do not forget to assign the form property "StyleBook" with the name of your StyleBook component).

88 Or you provide one or more style-files with your application and then load those you want into the StyleBook at runtime. Thus, e.g., the user can select a style that he likes. You can do this, for example, as the following (the path must certainly be adapted to your program environment): StyleBook1.Resource.LoadFromFile('D:\LunaStyle.style'); If you want to assign a style to the entire application, you can use the TStyleManager, e.g., at the create-event of the main form: TStyleManager.SetStyleFromFile ('D:\LunaStyle.style'); Even forms that are generated later at run time, will then have this style. To get it work, you must include the unit "FMX.Styles" in your units-list. e) Understanding FireMonkey-Styles The visible components in FireMonkey basically do not know how they should represent themself. For this, they need the style information. The so-called FireMonkey primitives are derived from TControl and can only represent their basic form as such. Only the TStyledControl, which is also derived from TControl, can draw itself with a style. Here is the overview:

89 TControl3D and subsequent classes have also been derived from TControl. These 3D components have nothing to do with the styles. Here, the representation is made according to the selected "material source", but for this we will come back later in the chapter on 3D programming. How does a component find its style? This depends on whether the component has assigned a value in the property "StyleLookup" or not. If there is a value, the component searches for a style element of the same name if a StyleBook exists. If so, this style description is used to draw the component. If there is no StyleBook, or if the value is not found in the StyleLookup property, a StyleName is constructed to search for. For this purpose the name of the class is used without the leading "T" (i.e. from "TEdit" the "edit") and supplemented by the word "style". Without a special StyleLookup assignment, a style named "editstyle" is searched for. First it searches in a possibly existing StyleBook.

90 (editstyle in RubyGraphite.style) If the component does not find it there, it searches in the "Defaultstyles". These are the styles built into Delphi that are always there, even if you do not have a StyleBook in the program. Depending on the operating system (Windows 7, Windows 8, Windows 10, macos, etc.) different "default styles" are searched there. If it can not find anything here, the component tries to find a style name using the same search method on the basis of the parent class. If this is not found, the component remains ultimately invisible. However, this will apply only in cases where quasi-proprietary components have been created, and the component with no named style also has a parent that also has no assignable style. So if you are not a component developer, you can forget this problem directly, it will never concern to you. By the way, you can change the styles as desired at the runtime of the program, and the redrawing is then performed on the basis of the previously described method. Since there are always problems with the differentiation of "StyleName", "StyleLookUp" I will try to make it clear: The StyleName describes the style itself, it almost represents the style description. StyleLookup tells the component what style to draw. You usually use the StyleName in the Style Designer and the StyleLookUp in the Object Inspector (where you normally do not enter a StyleName).

91 Typically, the base for a style element is the TLayout, which can contain more primitives or other style elements. However, there are also special style objects that can be used to form the container for other style elements, such as the TButtonStyleObject. These special style objects can be selected directly from the tool palette starting with Delphi 10 Berlin (previously you had to export the whole style as a file and edit it manually and then re-import it into the StyleBook): However, you can also group multiple components within a form, outgoing from a TLayout, and then assign a style name to the TLayout. If you then assign the StyleName to another component in the StyleLookUp property, the component is created based on the "Style" that you created with the Layout element within your form.

92 Chapter 3: Tips and tricks for Cross- Platform Development Section 1: Starting other programs Depending on whether you want to start another program on Windows, MAC or LINUX (or want to open a file with the default viewer) other routines are needed for each systems. This is achieved with the use of different units and the use of IFDEF directives. In the uses-clause, use the following: {$IF DEFINED (LINUX) or DEFINED (MACOS)} POSIX.Stdlib, $ENDIF} {$IFDEF MSWINDOWS} ShellApi, {$ENDIF} In the implementation section it looks as follows: procedure RunProg (prog: string); begin {$IFDEF MSWINDOWS} ShellExecute(0,'open',Pchar (prog),nil,nil,0); {$NIDIF} {$IFDEF MACOS} _system(pansichar ('open ' + AnsiString (prog))); {$ENDIF} {$IFDEF LINUX} _System (MarshaledAString (UTF8String (prog))); {$ENDIF} If you need to find out, where functions and procedures for the MAC or Linux

93 are located, look into the corresponding files in the following directories: C:\Program Files (x86)\embarcadero\studio\19.0\source\rtl\osx C:\Program Files (x86)\embarcadero\studio\19.0\source\rtl\linux C:\Program Files (x86)\embarcadero\studio\19.0\source\rtl\posix

94 Section 2: Get the program directory and program data directory You can find the program directory of the executable file both under Windows and the MAC by using the command "ParamStr (0)". In fact, the whole name of the executable file is stored here, but it's easy to identify only the program directory. The best is to use a unit, in which you set up the corresponding variables in the initialization section. Here's an example: unit MyData; interface uses System.SysUtils; var AppPath: String; AppName: String; AppExeName: string; AppIniName: String; ProgDataPath: String; Implementation begin AppExeName := paramstr (0); AppPath := ExtractFileDir (paramstr (0)); AppName := ChangeFileExt (ExtractFileName (paramstr (0)), ''); // Ohne Endung {$IF DEFINED (Linux) or DEFINED (MACOS)} ProgDataPath := IncludeTrailingPathDelimiter(GetHomePath) + '.config/' + AppName; AppIniName := ProgDataPath + PathDelim + AppName +'.cfg'; {$ENDIF} {$IFDEF MSWINDOWS} ProgDataPath := IncludeTrailingPathDelimiter(GetHomePath) +

95 'hastasoft' +PathDelim + AppName; AppIniName := IncludeTrailingPathDelimiter(GetHomePath) + 'hastasoft' + PathDelim + AppName + PathDelim + AppName + '.ini'; {$ENDIF} if Not DirectoryExists (ProgDataPath) then begin ForceDirectories(ProgDataPath); Please replace kindly here "Hastasoft" with your own company name or leave this part completely free. This supplement is especially recommended if you have developed many programs and the customers use several of your programs. The "Config" folder is a folder on the MAC where programs can store their configuration files. This folder is normally invisible in the Finder. You can of course use an alternative file manager that can show these folders (e.g. File IO for the MAC). You can turn the visibility of the normally hidden folders in the Finder on and off with: defaults write com.apple.finder AppleShowAllFiles YES // invisible with NO If you run the following source code, you will see the results at runtime on the different operating systems (of course, you would install your finished program in the usual places): ShowMessage ('AppName: ' + #13 + AppName + #13#13 + 'AppPath: ' + #13 + AppPath + #13#13 + 'AppExeName: ' + #13 + AppExeName + #13#13 + 'ProgDataPath: ' + #13 +ProgDataPath + #13#13+ 'AppIniName: ' + #13 + AppIniName); Windows:

96 MAC OS: Linux:

97 Section 3: Catch the program passed start-up parameters What under Windows can be done very easy with "StartParam := ParamStr (1)", is under the MAC OSX more difficult, because there it works quite differently. If you right-click on a file in the MAC-Finder and choose from the menu the command "Open with", the system starts the program and then sends at the same time a message to the program that it should open the selected file. So you have to set up a mechanism to ensure that messages can be received from your program. In MACAPI.AppKit is a NSApplicationDelegate available, which basically handled under MAC OS X the message "Open File". Unfortunately, this feature has not yet been integrated into the Delphi FireMonkey implementation. So there is currently no choice, as to make it by yourself. The following is the source code of the unit that does the implementation. In the main program then an "Open event" procedure must be implemented and be passed on generation of own delegates. It looks like so: unit hs_nsapplicationdelegate; // Will implement an own NSApplication delegate; by this // application:openfile: messages from MAC-OS-System can be handled. interface uses Macapi.ObjectiveC, Macapi.CoreFoundation, Macapi.AppKit, Macapi.Foundation, Macapi.CocoaTypes; type // Although we only need the OpenFile function here, we must also // still implement DidFinischLaunching and WilltTerminate, without // i cannot compile

98 // from Macapi.AppKit NSApplicationDelegateExtended = interface(nsapplicationdelegate) // create with Strg + Shift + G a own GUID // DON'T use the GUID below in your own program ['{2F5BD639-88DE-46F7-950A-D4469A125229}'] function application(theapplication: Pointer; openfile: CFStringRef): Boolean; cdecl; TOpenFileEvent = reference to procedure (const AFileName: string); TNSApplicationDelegateExtended = class(toclocal, NSApplicationDelegateExtended) private FOnOpenFile: TOpenFileEvent; public constructor Create(const AOnOpenFile: TOpenFileEvent); function application(theapplication: Pointer; openfile: CFStringRef): Boolean; cdecl; function applicationshouldterminate(notification: NSNotification): NSInteger; cdecl; procedure applicationwillterminate(notification: NSNotification); cdecl; procedure applicationdidfinishlaunching(notification: NSNotification); cdecl; function applicationdockmenu(sender: NSApplication): NSMenu; cdecl; procedure StartExtendedApplicationDelegate(const AOnOpenFile: TOpenFileEvent); var ExtendedDelegate: NSApplicationDelegateExtended; implementation uses FMX.Forms; constructor TNSApplicationDelegateExtended.Create(const AOnOpenFile: TOpenFileEvent); begin inherited Create; FOnOpenFile := AOnOpenFile; procedure TNSApplicationDelegateExtended.applicationDidFinishLaunching( Notification: NSNotification); begin // Dummy function TNSApplicationDelegateExtended.applicationDockMenu( sender: NSApplication): NSMenu; begin

99 // dummy function TNSApplicationDelegateExtended.applicationShouldTerminate( Notification: NSNotification): NSInteger; begin inherited; // dummy procedure TNSApplicationDelegateExtended.applicationWillTerminate(Notification: NSNotification); begin // Nicht FreeAndNil, verwenden, sonst gibt es Fehler!! FMX.Forms.Application.Free; FMX.Forms.Application := NIL; function TNSApplicationDelegateExtended.application(theApplication: Pointer; openfile: CFStringRef): Boolean; var Range: CFRange; S: string; begin Result := True; Range.location := 0; Range.length := CFStringGetLength(openFile); SetLength(S, Range.length); CFStringGetCharacters(openFile, Range, PChar(S));

100 TRY FOnOpenFile(S);

101 EXCEPT FMX.Forms.Application.HandleException(ExceptObject); Result := False; END; procedure StartExtendedApplicationDelegate(const AOnOpenFile: TOpenFileEvent); var NSApp: NSApplication; begin Assert(ExtendedDelegate = nil); NSApp := TNSApplication.Wrap(TNSApplication.OCClass.sharedApplication); if Assigned(NSApp) then begin ExtendedDelegate := TNSApplicationDelegateExtended.Create(AOnOpenFile); NSApp.setDelegate(ExtendedDelegate); end. In the main form, the following must then happen: procedure TF_Main.FormCreate(Sender: TObject); begin {$IFDEF MACOS} StartExtendedApplicationDelegate (OnOpenParaFile); {$ENDIF} In the form-declaration, in the private section: private { Private-Deklarationen } procedure OnOpenParaFile(const S: String); In the implementation-section: procedure TF_Main.OnOpenParaFile(const S: String); begin if (s <> '') and fileexists (s) then begin memo.lines.loadfromfile(fn);

102 Unfortunately, it's a bit complicated, but it works. It should also be noted that it is necessary to enter in the info.plist the information, which types of files your program will be able to open. Here is an example of a supplement to the info.plist file which gives the MAC- OS the information that your program can open text files and.xml as well as source code files: <key>cfbundledocumenttypes</key> <array> <dict> <key>cfbundletyperole</key> <string>editor</string> <key>lsitemcontenttypes</key> <array> <string>public.plain-text</string> <string>public.source-code</string> <string>public.xml</string> </array> </dict> </array> Without this, the Finder does not provide an entry in the "Open With menu" for your program name. But that does not prevent other programs instead of the Finder to transmit parameters to the program for opening files. For example, my file-manager "File IO for MAC" starts every program and gives at the same time a startup parameter to the program (this is managed by the MAC system in the background).

103 Section 4: "Hello World" - Multilingual programs and new markets The Apple App Store is ideal for selling your programs internationally and it can thus open up entirely new markets. For this purpose you should not only offer your program in your own language (in my case German), but also offering an English language version. For this intention, FireMonkey helps us in a very simple way with the TLang component, of course, in a cross-platform way. If you have developed your application, add a TLang-component to the main form. Example: Double click on this TLang component, it will open the following dialog:

104 You might be surprised that even the entry "Öffne mich Mac" is offered. This text is from the view "OS X Desktop". But it will show up only, when I have clicked on the button"scan for strings" here again. You must always do so when you add new controls to the form and want to edit these texts in the languagedesigner. In the field "Two-letter language code" enter "en" and click the "Add" button. The dialog will then change its appearance and beside the recognized text an input field is now available for each entry. There you can enter the English text equivalents: Now simply close the dialog. The changes are applied directly. To switch now from the standard language to English, you have to do this with a software command. A user would naturally choose his language on a menu entry. You can save his choice in the program by an entry in the ini-file and restore it at the next launch. In order to demonstrate it, we do this directly at the program start in the FormCreate event: procedure TForm13.FormCreate(Sender: TObject); begin

105 Lang1.Lang := 'EN'; WARNING: If you write "en" in lowercase, it does not work. You must enter the language code here in the uppercase as shown above. The form looks like this after program start: What you can see here is that the text of the form ("caption") is not covered by the TLang component, not even when you use the "Add" button on the right side of the Language Designer dialog to add an entry with a translation for "Form13" manually. You must, therefore, make the changes in the source code by yourself, such as: procedure TForm13.FormCreate(Sender: TObject); begin // Set default language Lang1.Lang := 'EN'; // Depends on used language: if Lang1.Lang = 'EN' then begin Caption := 'Title'; if Lang1.Lang = 'DE' then begin Caption := 'Überschrift'; Even menu texts are not translated. The main menu entries are shown in the

106 Language Designer and they are editable, but there are not translated at run time. You must - as long as this bug is not resolved in Delphi - make a separate procedure, where you can assign each menu item with the needed text (i.e. "mnu_optionen.text = 'Options', etc). Let's hope that the menu items are covered by this component in a subsequent version. If a component should not be translated, you can disable the setting "AutoTranslate" in the Object Inspector. If you have multiple forms in the project, they will also be searched for strings, but possibly only after you have clicked on the button "Scan for Strings". This button must also be pressed again, when you add additional forms to your project. You need only one TLang component for your whole project, because every second TLang component would again search the entire project for strings and would add them to your project (doubling it). In any newly created forms at run time, you must use the form-create event to tell the TLang component which language it should use. It offers itself here to create a separate procedure so that you can switch between different languages at run time. But you can only change from the original language to other languages. You can only come back to the original language when you restart the program and use the original language as default. OR you specify a new language in addition to the original language, i.e., "Add Language" here with the switch "de" (when German is the default language). Since it obviously makes no sense to provide a translation then, it simply restored the original entries. In this case, you can also switch back to the original language at runtime. The data of the TLang-component will be stored in the the form in an unreadable encoded format by default. Alternatively, you can save the text outside of the file. WARNING: If you have already translated texts and then uncheck "StoreInForm" in the Object Inspector:

107 you will lose your previous work; there is no confirmation prompt. So, before you uncheck it, use "Save File" in the Language Designer dialog box to save your language file. This file contains all previously applied languages and automatically receives the file extension ".lng". At runtime, you can then load the file with "Lang.LoadfromFile (file name)" into the component. At the demo here, everything works as it should. In a larger application that I have provided with the TLang component, the component does not keep track of all translations. Therefore, I have saved translations as a text file (with the button "Create txt-file template") and then reloaded again for revisions. You can load this file back to the Designer, when you add a language by using the button "From txt file". Anyway, everything has worked satisfactorily at the end. Section 5: Apply sandboxing and Entitlements properly If you want to bring your application to the App Store, it must support the sandboxing model. From July 1 st, 2012 on, this is the duty. Therefore, we should talk a bit about the sandboxing model first. It's shown here how your application works with and without sandboxing: Without the sandbox, your application has full access to all the files and folders of the operating system (it might be that your program must be run with

108 administrator rights for some actions). You may then obtain access to documents folder, images or music folders at any time. Also, your application could write to the Application Bundles of other applications which so far is a problem for the security of the operating system. If your application only runs "in the sandbox", it does not realize what else is running around it and does not have access to the data outside the sandbox. There may be applications for which it's enough to play in the sandbox. But it is often that you want give the working results of your application to other applications or want have access to data-output from other applications. Here, the "Entitlements" come into play. If your application would also like to play outside of the sandbox, you need to request the appropriate rights. The fundamental rights can be set with Delphi under the "Project, Options", "Entitlement List" (here, again, note that this information is only displayed if you have set the MAC OS X as the target platform):

109 What most applications will probably need is the right to read and save files, over which one can get access through the dialog "Open" and "Save". This is also a setting where Apple lets you go through it if you not describe why it is needed when registering the application in the App Store. In contrast, if you need direct "read and write" access to the other mentioned folders (pictures, music, etc.), you must explain it exactly why you need these rights in itunes Connect. If you don't do this, it's quite probable that your application will be rejected (already happened to me). When you click on the "View Details" button in itunes Connect on the page of your application, you can edit the so-called meta-data of the application. This is the description of what your application does and you can add a few screenshots that shows your application. Under the section "App Review Information", there is a button "Add Entitlement": Here just click on it, select the required right and then briefly describe (in English, of course) why your application needs the right. It should also be really necessary or, at least, be comprehensible.

110 It is important to know that you can request more rights than you can select in the Delphi permission list. Indeed, it is possible to request a right that your application can read or write to a specific folder, for example, the desktop-folder. However, Apple will normally not approve it, and so, according to my experience so far, these extensions have only theoretical relevance. In this respect, I have refrained from further explanations here. In the previous version of the book (for XE7), there were illustrations of how to add these extended privileges to the Delphi Entitlements list, and how to manipulate the provision manager to not override the manually provided information. The book also had a chapter on working with App-Scoped-Bookmarks, which allows a persistent access to already opened folders or files outside the sandbox and in the appendix a sandbox unit.

111 If you need this information for some reason, the previous version of the book with the corresponding information is still available for purchase at Amazon for a small amount:

112 Section 6: Using MAC APIs (POSIX, CORE and Cocoa) in Delphi The MAC OS X operating system essentially works with 3-layer systems: POSIX CORE API COCOA Framework While the first two layers are addressed over a conventional C-interface, the COCOA layer is accessible via a special Objective-C interface. A set of functions is ultimately in all or several layers. For example, you can query the computer name with a POSIX function (gethostname) or the COCOA interface NSHost (Host.Name). In the following, we will focus on the individual layers:

113 POSIX The POSIX interface offers typical low-level operating system functions, which can also be found in other Unix or Linux systems. So you can, for example, ask for the name of the computer on which your program is running, with the POSIX function "gethostname". This function is defined in the "Posix.UniStd.pas". To be more exact, the function is to be found in the "UniStdAPI.inc". It's worth it saying here some words on the structure, with which Embarcadero has implemented these API functions. Under C:\Program Files (x86)\embarcadero\studio\15.0\source\rtl\posix you can find the POSIX folder. It has a subdirectory called "OSX". The concrete implementations are found in the ".INC"-files (.INC stands for "include"). If you look at the individual units of the POSIX folder, for example, you will find IFDEF declarations in the "Posix.Stdlib.pas" in the following way: {$IFDEF MACOS} {$I osx/stdlibtypes.inc} {$ENDIF MACOS} {$IFDEF LINUX} {$I linux/stdlibtypes.inc} {$ENDIF LINUX} The Linux folder does not exist yet, but we may be sure that Embarcadero is working on a Linux implementation. The function in the UniStdApi.inc is implemented: function gethostname(name: MarshaledAString; namelen: size_t): Integer; cdecl; external libc name _PU + 'gethostname'; {$EXTERNALSYM gethostname} To make them suitable for Delphi, we can do this as follows:

114 Uses Posix.unistd.pas, function mac_getcomputername: string; Implemtation function mac_getcomputername: string; var buf: Array [0..255] of AnsiChar; begin if gethostname(buf, sizeof (Buf)) <> -1 then begin Result := UTF8ToUnicodeString(buf); if pos ('.local', Result) <> 0 then begin Result := copy (Result, 1, pos ('.local', Result)-1); Probably the computer name on Unix is significantly shorter than the 256 characters that I have reserved here, but I do it in a safe way since I don't know how it turns out to be. For MAC OS X, the return name is normally supplemented with a ".local", under which the MAC can be addressed overall in the network. For our purposes, however, we only need the name as it will usually appear in the system. A similarly useful feature that you could still implement from the Posix.unistd would be the "getlogin" function, with which you can query the user name. Since we don't need here any buffer, in which the name must be stored, we can use this function directly as: strusername := UTF8ToUnicodeString (GetLogin).

115 COREAPI You will find most of the core API's in the unit "MacApi.CoreFoundation.pas". Again, take a look at the Delphi folder structure. The MacApi.CoreFoundation.pas can be found at: C:\Program Files (x86)\embarcadero\studio\15.0\source\rtl\osx Also look once into the unit, which is a short unit that integrates a number of include-files, such as the CFString.inc file that implements some CFString functions in Delphi, which we need to work with CFString objects. Also the Core API is accessed via a C call systematic. The main difference with the POSIX functions is that the "Reference counted objects" are behind the socalled Core API. It means that objects sometimes even COCOA objects are behind functions or data structures. If you want to use strings as passing parameters here, they cannot be Delphi strings, but CFStrings, reference counted string objects. Here is an example that demonstrates the use of the CFStrings: procedure mac_showmessagenative (ahead, AMsg: string); var CFHead, CFMsg: CFStringRef; AResult: CFOptionFlags; begin CFHead := CFStringCreateWithCharactersNoCopy (NIL, PChar (AHead), Length (ahead), kcfallocatornull); CFMsg:= CFStringCreateWithCharactersNoCopy (NIL, PChar (AMsg), Length (amsg), kcfallocatornull); try CFUserNotificationDisplayAlert (0, 1, NIL, NIL, NIL, CFHead, CFMsg, NIL, NIL, NIL, AResult); finally CFRelease (CFHead); CFRelease (CFMsg);

116 Here the Core-Foundation function "CFUserNotifiationDisplayAlert" is implemented. We use here only a very simple implementation. If required, the alert-function could even been shown with a time-out value, with a further button and user-defined text for the button. The exact skills of the function can be seen in the MAC Developer Library on the following page: The "CFStringCreateWithCharactersNoCopy" function comes from the MacApi.CoreFoundation.pas (or CFString.inc). It creates the string object. All functions whose names contains a "Create" or "Copy" include, when they are called, that the reference-counter to the object is increased by the value of "1". After using the objects, you must then release them with "CFRelease" so that the reference-counter can be reduced by the value of "1" again. When the referencecounter is reset to zero, the object is total released. If you not do it, you will retain residual objects in the memory that will stay after your program ends. I do not know how for the programs for the MAC App Store are checked for such shortcomings. I would advise to work carefully with such objects. One important information for functions that have a "Get" in their name: Their objects are not copied or new created. You just use the original actually. Directly after using the "Getxxx" function, you have to call the function "CFRetain" before you continue with the string objects. CFRetain, then, also performs an increase of the reference-counter and assures you the further use of the object. After completion of the work with the object, you give it free with "CFRelease", which let the reference-counter decrease by "1".

117 COCOA API The API's from the COCOA Framework are specifically tailored for the use with Objective-C. You will find many objects and functions in the "MacApi.Foundation.pas" implemented, for example, the entire URL functions I use in the HSW.FMXSandbox.pas unit. Look once in this MacApi file, you find it in the following folder: C:\Program Files (x86)\embarcadero\studio\15.0\source\rtl\osx The COCOA "objects" (Objetive-C classes, meta-classes and protocols) are usually implemented as interfaces. Therefore, you will find two interface implementations for the NSString object / class, one as NSString = interface(nsobject) and as NSStringClass = interface(nsobjectclass). The same applies, for example, for NSURL and NSURLCLASS. It is important to know it because you will sometimes need functions from one and the other interface. By the way, a lot is implemented here, but not all. Sometimes you need to upgrade individual functions through a re-implementation by yourself, as I have made it, for example, in the HSW.FMXSandbox.pas unit. But again, let's look at an example of how to use COCOA objects. Here we use a NSWorkspace object (the unit MacApi.Appkit.pas must be included). However, I will show you first how it does not work, because that is what you would normally try (and is often seen in forums where people asks why this does not work): var URL : NSURL; Workspace : NSWorkspace; begin URL := TNSURL.Create; URL.initWithString(NSSTR('

118 Workspace := TNSWorkspace.Create; Workspace.openURL(URL); URL.release; Workspace.release; It will not work because as a result of the Delphi Objective-C bridge, just a "Raw" object is supplied back, which is not usable in this case. And for the Workspace object, it is important, that only one shared workspace object is available for each program, to which must be accessed via the "sharedworkspace". Details to this extremely useful object can be found here: The proper use of it looks like this: var URL : NSURL; Workspace : NSWorkspace; begin url := TNSURL.Wrap(TNSURL.OCClass.URLWithString (NSSTR(' WorkSpace := TNSWorkspace.Wrap (TNSWorkspace.OCClass.sharedWorkspace); Workspace.openURL(URL); There is no need to release anything because nothing was created. Only variables (objects) with content were set. Although the most COCOA objects are reference-counted, this works automatically usually. In the example case, therefore, neither a "retain" nor a "release" after the use of the object is required. In COCOA objects, it is required to work with "Release" functions only in exceptional cases, which simplifies the working with these objects very much.

119 Chapter 4: Requirements for Cross- Platform Development Section 1: Setting up Windows PC and MAC PC You must have a Windows PC and a MAC, which are connected via a network (wireless or wired network). Alternatively, you can also set Windows in a virtual machine on the MAC. I like the latter solution not so much because I've run on my MAC different partitions with different MAC OS X versions according to my needs. And then it's an advantage to have your own Windows PC with Delphi installed there. Preparation You will find on your Windows PC, under the following directory, C:\Program Files (x86)\embarcadero\studio\19.0\paserver the file "PAServer19.0.pkg". Copy this file to the MAC (e.g. on the desktop there). The file "Setup_paserver.exe" - is not needed (it is used, if you want to perform on another Windows machine a remote debugging). Small digression: How to set up a drive connecting from your Mac to your PC: Open the Finder and choose the "Connect to Server" command from the menu "Go to":

120 Click on "Connect". If you do the connection for the first time, this dialog will appear: Enter the user name of the Windows PC and below also the server password (not the password of the MAC-PC). If the connection works, you have a new volume (drive) available on the MAC. You can share your files with this drive. Then, double click on the.pkg file on the MAC and it will be automatically extracted. Double-click then on the unpacked file "Setup_paserver". The following setup program starts, which installs the PAServer on the MAC. The PAServer program is an interface program that Delphi needs to transmit files over a TCP-IP connection from your Windows PC to the MAC and then to start them there.

121 The PAServer is found, after installation, on the MAC in the program folder: /Applications/PAServer19.0.app On the Internet, it is also described in a docwiki how the server should be installed and run: To start the server, go to the Applications folder and launch the application "PAServer 19.0" A console window will be open then.,there you just confirm the start with return if you don't want to assign a password (in my opinion that is never needed). Then the system will ask you to enter your admin password. If you have done this, the server program is ready and waiting for a connection. Delphi transmit then the MAC application produced on the Windows PC, by using the PAServer, to the MAC into the so-called "ScratchDir". This can usually be found here: /Users/YourUserName/PAServer/Scratch-Dir.

122 Section 2: Enabling MAC OSX Platform By default, the MAC Platform is automatically available as a target-platform in a "Multi Device Application" in the Project Manager. If you have once deleted it or don't find it in a project that you have taken over from XE6 or earlier: you should add the platform to your project with a right-click on the "Target Platforms" in the Project Manager and select the command "Add Platform" from the pop up menu. If you do this for the first time, the platform must first be established. You may also need to make settings for the SDK. For this purpose, the PAServer on the MAC must already be running. Click, with the right mouse button, on the platform name and select "Edit SDK" command: Note: It could be, that before the dialog below appears, you have to input a profile-name. And now to the dialog:

123 For "Host-Name", I recommend, instead of the name of the MAC PC, to use the IP-address from the MAC in the network (you will find the IP address of the MAC under "Control Panel, Network"). The connection works faster whereas sometimes it works only with the IP address in networks mixed with wired and wireless connections. Note: If the IP address is dynamically assigned by your router, the IP address will change at the next day, when you work again with your connection. If the submission of the files to the MAC does not work (it then only gives the message "Error" without further explanation), this should be the first thing to check. TIP: You can also adjust the system settings of the MAC, so that a specific IP address always will be used here. Then you will never need to change anything here again (I have done it like that and all works excellent!). Use the port number here as specified. Leave it blank under password or enter a password for the PAServer if you have setup one (not necessary usually and it makes things only complicated). But now, let's go back to the "Edit SDK" dialog. Here, you can select a suitable SDK., from which there is normally one or several available to choose. Normally, select the newest. Or select an older one if there are problems with the latest SDK. SDK versions are directly related to the respective OS versions.

124 If you have added a platform, it could look like this in the project window: Important note: Depending on whether you select the target platform "Windows" or "MAC OSX", the presentation of the project options dialog also changes. Take a special attention here to the "Version Info", because the info.plist file will be created with that later, which must accompany each MAC program. In the project options the "Entitlement List", where you can specify which rights are available to your program, is also important. In particular, if you want to distribute your programs on the APPLE App Store, you should choose carefully the settings here. From the Entitlement-List, Delphi generates the ".Entitlements" file that will be distributed with the program (which is especially important for the sandboxing model). The Entitlement-List:

125 The Version-Info: If needed, you can add a new key here. Right-click on the table header "Key" (shown here in yellow): After choosing "Add Key", the below dialog will then appear where you can enter the new key-name:

126 Unfortunately, you can only enter single values in the grid-list. If you add an array structure, this looks good at first sight: However, the editor inserts an additional <String> entry here so that the key group ultimately can't be utilized. Therefore (and as long as it is not fixed in Delphi), you must edit the info.plist file by yourself in a text-editor so that the entries can be valid. Section 3: Provisioning and deployment (MAC) Under menu "Project", call the command "Deployment" and the register "Deployment" will be shown. Here you can add more files to your project. They can, for example, be HTML help files, plain text files or graphics that are required by your program. This is a really practical thing: The.rsm-file is a file required only for the debugger. If you create manually a.dmg-file (Disk Image) later, i.e., for distribution outside the app store, you must delete the file in the scratch-directory from the MacOS folder before. It shows below how to create the.dmg file. The.rsm-file is also not required for the distribution in the MAC App Store. Therefore, for all completed projects, delete

127 this file from the application bundle as far as Delphi has not yet done this for you. If Delphi has created the program, Delphi will transmits it to the MAC into the Scratch-Dir directory that you can find normally under "/Users/YourUserName/PAServer/Scratch-Dir". The executable file is usually located in the "MacOS" folder. Under "Contents", you will find the "info.plist" and the "Entitlements.plist". The lybcgunwind.1.0.dlyb file, will needed in the delivery version of the program, otherwise it won't run.

128 1. Submission to the APPLE App Store For this, you have to switch from "Normal" to "Application Store" under the target platform MAC OS X entry: Under the menu "Project, Options, Provisioning", check whether "OS X Application Store" is selected as the build-type. And of course, you should use the "Release configuration". In the two edit fields, make entries as listed below: The installation profile "3rd party Mac Developer Installer" is a certificate that is used to sign the installer-file. The "3rd party MAC Developer Application" is a certificate, that is used to codesign your application. First check in the "Keychain Access" on your Mac if you have already installed the required certificates on your MAC:

129 If you don't have such a certificate yet, you can get one from Apple, but you definitely need an Apple Developer ID for it (see below, under 3a). If you have called the command "Deploy <Projectname>" in the Delphi Project menu, Delphi will transfer the required files to your MAC and call the codesigning tool that initially signed the executable file (you will be prompted to allow this). Right after that, Delphi calls the "Product Build Tool" that produces a so-called "Package" and a file with the extension ".pkg" will be created. This "package" is then the installation-file. And that is the reason why it is also signed with the "Installer Certificate". You can then upload this completed package to Apple with the Apple program "Application Loader". Firstly, however, you must create a data-entry for your program through itunes Connect and complete your input there with "Ready to upload binary". After two more confirmations for data security, you can then upload your application (the package) with the Application Loader: If your program is to be reviewed by the Apple employees, it usually takes 3-7 days until an assessment is carried out. To stay informed of the progress, you can use a free app from Apple (ITC- Mobile). Below is a screenshot of my iphone. This allows you to manage the apps to a certain extent and examine your sales.

130 The programs with the green dots are already in the store. Those with orange dots are either waiting for a review or are just in review. In the grey box, you can see the "OS X" or "ios" label, which will indicate if it is a program for the MAC or iphone / IPad. Under the "Sales / Trends", you can check how many products have been sold for a day or for a week. Also, you can see the countries in which you have sold your programs. Surprisingly, I was able to find buyers in the US, Russia, Thailand, Japan, Italy, Mexico and Slovakia even with my only Germanlanguage programs. After a month, you will get one or more "Financial Reports" via from Apple, which you can view over the web in itunes Connect. There you can see how many units you have sold in the countries and how much money is owed to you. And you will see when the next payment date is and when Apple will transfer your share. But the money will only be paid when it is counted that you should get more than $ 150. The first regular payment date is between 1-2 months. A tip: Before you load a program into the Apple store, look at Apple's "App Store Review Guidelines".

131 Here is the link to:

132 2. How to create a.dmg file for distribution outside the Apple App Store I sell my programs even without the App Store. You can do this also as follows: After you have created with Delphi a MAC OSX release version (with the project setting "Normal" and not "App Store"), run the "Disk Utility" (Applications folder, "Utilities) on the Mac. Select the "File" menu and select "New", "Disk Image from Folder": The Finder dialog is displayed, so then can navigate to the directory where your program is: Select the program file and click on the button "Image". The following dialog will be displayed:

133 I recommend removing the extension ".app" and choosing the location of the "desk". The TEditor.dmg file created in this case, can be now distributed to your customers over the Internet. After downloading by the user, the customer double-clicks on the.dmg-file and drags the file into the program folder. The program is then installed.

134 3. Ho to create your own setup package with the Application Developer ID / Installer It could be another possibility to sign the program with the "Developer Application ID" certificate, and then create your own setup package and sign this with the "Developer ID Installer" certificate. What are the advantages? Well, from MAC OS on, Apple uses the so-called "Gatekeeper" function that can be enabled in the system settings under the "Security", "General" tab: Even if it is written "Allow Download" there - it probably means "Run". Because you can download a program which is located in a.dmg file from the Internet and even drag the application into the Applications folder then. If the user has activated the settings shown as above and is now trying to run your program that you have sold as described above under number "2.", a dialog will be shown as follows: So if you want to play it safely, you need to perform your program with the

135 certificates described above. In your Keychain Access, you must have the following (colored) certificates: If you already have these certificates, you can skip the next subsection and read more in "Working with CodeSign tool and Package Maker" under "3 b)". a) How to request a Developer ID certificate and an Application Developer Installer ID If you do not already have such certificates, log in under and click on "Member Center" in the upper right corner. Then click on the link shown below and you will be forwarded to the area where you can manage your certificates: Then click on the table: "MAC App's, Certificates". This brings you to the page to manage MAC certificates. Click on the plus button on the right side at the top, then you lead you to the page where you can choose the certificates according to your needs.

136 Ultimately, you need all certificates that are offered here (if you also want to distribute your app also with the App Store). For our purposes, it is enough when you ask for the lower certificates ("Developer ID", not visible in the screenshot above). Download it to your MAC and double click on the file so that it will be installed into your Keychain Access (or drag it from the download-folder to the Keychain Access-window). I don't want to describe all the steps here, but maybe two tips on this: Tip 1: Before you can install your certificates, you need the "WWDR Intermediate Certificate" and the "Developer ID Intermediate Certificate". This notice is also displayed on the page shown above if you scroll down. Tip 2: In order to be able to create your certificates, you need a "CertifacteSigningRequest" file in general. Where do you get them from? Use the program "Keychain Access". Go to the menu "Keychain Access", "Certificate Wizard" then "Request a certificate from a certificate authority":

137 The following dialog will be displayed: Once you have finished this dialog, you will receive the file requested. In my case, I had to create this file several times because different request files were needed for the different certificates. TIP: after I got my Developer ID's and this was transferred to the Keychain Access, it was first displayed that they were invalid because it were signed by an "Unknown Certificate Authority". It helped when to wait: 24 hours later, I downloaded the certificates again from the certificates area and re-installed it. It was then all perfect. b) Working with the code-signing tool and Package Maker If you have Delphi run with your MAC OS X profile and created your MAC program, you must sign it then. Since the program is not for the App Store, you must select in the project options "OS X - Normal" as 'Build-type". After running the program and transferring it to the MAC, you must use the code-signing tool manually to sign your package. You can use it by invoking it from the command line. To do this, open another terminal window and change to

138 the directory where your application resides. Then type in the terminal window: codesign -s "Developer ID Application" TEditor.App Here, of course, replace "TEditor.App" with the name of your application. You'll again be prompted to allow the signing: Now, you have signed your program, but how can you create the setup package? You can do this with the "Package Maker" which you will no longer find by default on newer MAC OS versions. So you must download it from Apple. This is done in the download area ( Search here for "Auxiliary Tools for X-Code". Then, install the downloaded program package, open it and start the Package Maker program. For MAC OS X Maverick or later, the program cannot be used (apparently) because it keeps crashing. I've simply installed it on an older MAC OS X version (Mountain Lion) and used it there. Here you can see that it could sometimes be useful to have also older MAC OS Systems in use (I have this on several of

139 partitions on my Mac). If that's too much trouble, you must use one of the commercial programs, with which you can create installation packages for the MAC. If you can use the Package Maker, proceed as follows: At "Certificate", you click on the arrow, and enter your "Developer ID Installer" certificate. Also, you can make basic settings, e.g., the title of the setup, where the program may be installed, and so on. Next screen shot: just drag your program from the Finder into the left side of the window or click on the button beside the line "Install" and go to your folder where the compiled and already signed program is: So you can easily use this dialog to make the necessary settings for your setup package.

140 If you click on "Edit Interface" in the upper right corner, a dialog will appear, where you can select the individual installation steps in detail: Here, you can directly insert your contract text or refer to a file. The license information must be accepted by the user, otherwise the program cannot be installed. Then click on the button "Build" or "Build and Run", then your setup package is created. You will be prompted again to allow the signing and then your setup package is ready. And it works well with the gatekeeper if the user should have set the installation restrictions described at the beginning of this section. For me, this is certainly now the preferred distribution method (I used it also for my MAC programs created previously with Lazarus). Note: When running the setup-program on my MAC, the PackageMaker-Setup installed again and again the program into the directory where the program was developed. I could not stop that, but ultimately it has no negative impact, because on other MAC PC's it works as expected.

141 Chapter 5: Cross-Platform development with Linux The setup and development of programs for Linux is much easier than for Mac OS X. It should be noted that the Enterprise version is required to develop Linux programs. Another limitation is that you can only develop console programs, so no applications with a user interface for the desktop. It is truly welcome that Delphi is now able to develop Linux programs. And it is said that one can achieve a lot with it. But it is a pity, however, that Delphi does not have the possibility to develop desktop programs for Linux. However, here is already mentioned that you can use the FMXLinux-Add On from KSDEV-Software, with that you can also develop desktop programs for Linux. Embarcadero tell us, that Ubuntu and Red Hat are supported as Linux-OS, but it is assumed that the PAServer program also runs under Suse Linux or other Linux derivatives. However, you need a 64-bit Linux operating system, but this should not be a problem. What should generally be considered in the Linux64 platform is the fact that no AnsiStrings are supported. In addition, Automatic Reference Counting (ARC) is also used for Linux (as for the mobile platforms) for memory management. All pointers are in Linux 64 bit, but an integer is still 32 bit.

142 Section 1: Setting up Windows and Linux-PC You need a Windows and a Linux PC that are connected over a network (WLAN or cable network). Alternatively, you can set up Windows in a virtual machine on the Linux machine or you can set up a virtual machine with Linux on the Windows PC. I personally work now with Linux (Ubuntu LTS) as main computer, so that I have here in a VirtualBox a Windows 10 running. Preparation On your Windows PC, you will find the following directory C:\Program Files (x86)\embarcadero\studio\19.0\paserver Copy the file "LinuxPAServer19.0.tar.gz" file to the Linux PC (for example, to the desktop). A small excerpt: How to set up a drive connection of your Linux PC to your Windows PC: On Linux, start the file manager and select "Connect to server" on the left. The following dialog will then appear, which allows you to connect to your Windows drive: Click "Connect". Note: The name of the computer name does not work sometimes. Then you have

143 to enter the IP address of the computer instead of the computer name (here ew1), so I still had success. If you set up the connection for the first time, this dialog appears: You can first try to set up the" anonymous connection". Which access options you have on the Windows PC depends on how you set up the network share. If this does not work, try "registered user". Under "User name" you have to enter the current user name of the Windows PC and under "Password" also the password there (not the password of the Linux PC). If the connection has worked, a new medium (drive) is available on the Linux:

144 You can use this drive to exchange your files. Then, on the Linux PC, doubleclick the.tar.gz file, then the Linux Archive Manager is started: Here you can unpack the contained files by clicking on the "unpack" button. As Target you choose your home directory (or any other one where you have unlimited write permissions). Then open a console on the Linux PC, change to the directory where the paserver program is located and start it with the command:./paserver

145 A console window ("Terminal") is opened, where you simply confirm the execution with Return, if you do not want to assign a password (I do not think it is necessary). Here the result that is displayed on my Linux-PC (I don't have installed it in the home directory, but on an external hard drive, which is attached to Media). When you have done this, the server program is ready and waiting for a connection. Also under Linux the PAServer-program represents an interface program, which Delphi needs to transfer the generated files from the Windows PC to the Linux computer into the so-called "Scratch-Dir" directory, where it than will be started. This is usually found here, where "UserName" would be replaced by your current user name: /home/username/paserver/scratch-dir. If necessary, you can also switch to this directory in a new console and start your program manually (do not forget to enter "./" before the program name). Also useful are the query options of the PAServer program, which can be used for example to show the available IP addresses of the Linux machine or the directory of the Scratch-Dir location:

146

147 Section 2: Enabling the Linux-Platform As I said before, by default, you can only create console applications for Linux: Likewise, after selecting this application, the Linux platform is not activated automatically. Add the Linux platform to your project by right-clicking on the "Target Platforms" entry in the project management and choosing "Add Platform" from the pop-up menu. If you do this for the first time, the platform must first be set up. You may still need to make settings for the SDK. To do this, the PAServer must already be started on the Linux machine. Right-click on the platform name and select "Edit SDK":

148 Before I go into this dialog: Possibly you will be prompted to assign a profile name. This then looks like this: In the case of "hostname", instead of specifying the name of the Linux computer, I advice to enter its IP address (the IP address of the Linux PC can be found under Control Panel, Network). For the rest, I would like to refer to the explanations already made during the establishment of the MAC SDK. But now back to the "Edit SDK" dialog. Here you can choose between one or more SDK's. Normally, select the latest SDK. Select an other SDK, if there are problems with the latest SDK. SDK versions are directly related to the respective Linux versions.

149 This will meet now all requirements and you can develop your first Linux console application.

150 Section 3: Provisioning and deployment (Linux) In the Project submenu, use the deployment command to access the deployment tab where you can add additional files to your project. Simple text files or graphics that are required by your program. This is a really practical thing, so you have everything in the overview: Here is just the application itself for transfer to the Linux computer provided.

151 Section 4: A first Linux-Console-Application If you selected "console application" in Delphi under "File", "New", "More", you will get the following program (which I have already supplemented with the entry "Writeln ('Hello World!')": I have already activated the Linux platform here, as already described above. When you start the program, you will see the following output in the Delphi event log window: Note: The output is only displayed in the Event Log window when the application has been run in debug mode. You activate the event log window via the menu "View", "Debug window", "Event log".

152 If you do not start the program in debug mode, the output is displayed in the terminal window of the PA server. Sometimes there are situations where you have to start the Linux program directly on the Linux machine, for example when the program will wait for user input, e.g. via ReadLn. The PAServer terminal window is not able to do this. We can look at this directly at the next project.

153 Section 5: Linux-Server-Console-Application and Client-Application Next, we will create a very simple server server-client application using the Indy components. The client program will connect to the server program and may submit text to the server, which is then displayed in the terminal window. It can also query the server program on which operating system it is running and display the result in a memo window. To do this, we create a console application and add the text as follows: program ServerApp; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, DMUnit in 'DMUnit.pas' {DataModule1: TDataModule}; var s: string; begin try Writeln ('Serverprogramm V.091 gestartet.'); Writeln ('Exit Prog by "stopserver" command.'); DataModule1.idserv.Active := True; if DataModule1.idserv.Active then begin writeln ('Server active on Port:' + DataModule1.idserv.DefaultPort.ToString); repeat Readln (s); until s = 'stopserver'; writeln ('Programm beendet'); except

154 on E: Exception do Writeln(E.ClassName, ': ', E.Message); end. We then add a DataModule to the program. Forms are not allowed, but DataModules are. Here we can add an Indy-TIdTCPServer component: For "DefaultPort", set the value "24600" in the object inspector. Then, click the "OnConnect", "OnDisconnect" and "OnExecute" events one by one in the Object Inspector: and add the source-code like follows:

155 unit DMUnit; interface uses System.SysUtils, System.Classes, // Indy IdBaseComponent, IdComponent, IDGlobal, IdCustomTCPServer, IdTCPServer, IdContext; type TDataModule1 = class(tdatamodule) idserv: TIdTCPServer; procedure idservconnect(acontext: TIdContext); procedure idservdisconnect(acontext: TIdContext); procedure idservexecute(acontext: TIdContext); private { Private-Deklarationen } public { Public-Deklarationen } var DataModule1: TDataModule1; implementation {%CLASSGROUP 'System.Classes.TPersistent'} {$R *.dfm} procedure TDataModule1.idservConnect(AContext: TIdContext); begin Writeln ('Server connected'); procedure TDataModule1.idservDisconnect(AContext: TIdContext); begin Writeln ('Server disconnected'); procedure TDataModule1.idservExecute(AContext: TIdContext); var cmd, txt: string; begin with AContext.Connection do begin IOHandler.DefStringEncoding := IndyTextEncoding_UTF8; cmd := IOHandler.ReadLn;

156 if cmd = 'cmd:displaytext' then begin txt := IOHandler.ReadLn; Writeln (txt); if cmd = 'cmd:getos' then begin IOHandler.WriteLn(TOSVersion.ToString); Initialization DataModule1 := TDataModule1.Create(NIL); end. If you have created the server program, start it, and in the terminal window you will get the following output: If you want to quit the program, press the Enter key once in the terminal window, enter "stopserver" and confirm with the Enter key. The message "Program terminated" appears. But let it run quietly, in the meantime, we create a client application that can communicate with the server program. At the design time the program looks like this:

157 The corresponding program code looks like this: unit Main; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo, FMX.Edit, FMX.Controls.Presentation, // Indy IdBaseComponent, IdComponent, IdGlobal, IdTCPConnection, IdTCPClient; type TFMain = class(tform) bnconnect: TButton; bndisconnect: TButton; cl1: TIdTCPClient; edsend: TEdit; bnsendtext: TButton; bnrequestos: TButton; Label1: TLabel; Panel1: TPanel; mosinfo: TMemo; Label2: TLabel; procedure bnconnectclick(sender: TObject); procedure bndisconnectclick(sender: TObject); procedure bnsendtextclick(sender: TObject); procedure bnrequestosclick(sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen }

158 var FMain: TFMain; implementation {$R *.fmx} procedure TFMain.bnConnectClick(Sender: TObject); begin cl1.connect; procedure TFMain.bnRequestOSClick(Sender: TObject); begin if cl1.connected then begin cl1.iohandler.defstringencoding := IndyTextEncoding_UTF8; cl1.iohandler.writeln('cmd:getos'); mosinfo.lines.text := cl1.iohandler.readln; end else begin ShowMessage ('Connect first'); procedure TFMain.bnDisconnectClick(Sender: TObject); begin cl1.disconnect; procedure TFMain.bnSendTextClick(Sender: TObject); begin if cl1.connected then begin cl1.iohandler.defstringencoding := IndyTextEncoding_UTF8; cl1.iohandler.writeln('cmd:displaytext'); cl1.iohandler.writeln (edsend.text); end else begin ShowMessage ('Connect first'); end.

159 At runtime you will have the following output: In the terminal window:: And below the Windows-FMX-program (which could alternatively also be created as a MAC-OS X application): You can download the demo programs here:

160 Section 6: Create an Application as Service (Daemon) From Windows, you may already know the "service", an invisible program that runs in the background and does not accept any input and does not generate any output on the screen. There is something like this under Linux, which is called "daemon". So if you want to run your server application in the background and do not have to input and output via the terminal (because, for example, the communication is only controlled via third-party programs), create a "daemon". This requires only minor modifications to your main program. This would be a very simple variation: program Daemon; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, Posix.Unistd, Main in 'Main.pas'; begin try if fork()<>0 then begin exit; while Working do begin sleep(100); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end.

161 The function "fork" from the unit "Posix.Unistd" is relevant here. With its call, it creates an exact copy of your program, only the standard input and output are ignored. You can find a description of fork here: If the return value of fork is equal to zero, it means that we are currently in the generated copy. And that is what we want to use, so the program continues. If the return value is <> 0, we are in the original process, which we want to quit, we simply do not need it, because the work is supposed to run in the background process. With "Exit", the original process is terminated at this point. To have the option to end the copy of the generated process (the daemon), we have a boolean variable "Working" in use here. This is preset with "True" and thus ensures that the program continues to run. If you set the variable to "False" later, the daemon is terminated. But how do you do that, when no input is available via the console? The simplest way would be to communicate over TCP / IP. Your client application can then transmit an agreed signal to the server program, which sets the working variable to "False". In the example from Section 5, this could be done in the OnExecute event of the Indy server component.

162 Section 7: Delphi units for Linux Here you can see which units you currently can use (April 2017) under the Linux platform. System-Units SysInit.pas System.Bindings.Consts.pas: this and following units have Live Bindings support System.Bindings.CustomScope.pas System.Bindings.CustomWrapper.pas System.Bindings.EvalProtocol.pas System.Bindings.EvalSys.pas System.Bindings.Evaluator.pas System.Bindings.Expression.pas System.Bindings.ExpressionDefaults.pas System.Bindings.Factories.pas System.Bindings.Graph.pas System.Bindings.Helper.pas System.Bindings.Manager.pas System.Bindings.ManagerDefaults.pas System.Bindings.Methods.pas System.Bindings.NotifierContracts.pas System.Bindings.NotifierDefaults.pas System.Bindings.ObjEval.pas System.Bindings.Outputs.pas System.Bindings.Search.pas System.Bluetooth.Components.pas System.Bluetooth.pas System.Character.pas: this unit has Unicode support at the codepoint level System.Classes.pas: basic classes for TComponent etc System.ConvUtils.pas: convert units of measurement System.DateUtils.pas: dates processing System.pas: the core unit System.Diagnostics.pas System.Generics.Collections.pas: as the name says, generic collections System.Generics.Defaults.pas System.Hash.pas: hashing support has been extended with file hashing System.HelpIntfs.pas System.IniFiles.pas: these clone the Windows INI files System.Internal.DebugUtils.pas System.Internal.ExcUtils.pas System.Internal.JSONHlpr.pas System.Internal.StrHlpr.pas System.Internal.VarHlpr.pas System.IOUtils.pas: support for modern file system access (input/output utilities) System.JSON.BSON.pas: this and the following units have JSON and BSON streaming support System.JSON.Builders.pas System.JSON.Converters.pas

163 System.JSON.pas System.JSON.Readers.pas System.JSON.Serializers.pas System.JSON.Types.pas System.JSON.Utils.pas System.JSON.Writers.pas System.JSONConsts.pas System.Linux.Bluetooth.pas System.Masks.pas System.MaskUtils.pas System.Math.pas: Core mathematical functions System.Math.Vectors.pas System.Messaging.pas System.Net.FileClient.pas: the "Net" units implement the HTTP client library System.Net.HttpClient.pas System.Net.HttpClient.Linux.pas System.Net.HttpClientComponent.pas System.Net.Mime.pas System.Net.Socket.pas System.Net.URLClient.pas System.NetConsts.pas System.NetEncoding.pas System.RegularExpressions.pas: these units have RegEx support System.RegularExpressionsAPI.pas System.RegularExpressionsConsts.pas System.RegularExpressionsCore.pas System.RTLConsts.pas System.Rtti.pas: Core RTTI access unit, or reflection support System.Sqlite.pas System.StartUpCopy.pas System.StdConvs.pas System.StrUtils.pas: core string processing utilities System.SyncObjs.pas: threads synchronization System.SysConst.pas System.SysUtils.pas: the most classic system utilities System.Tether.AppProfile.pas: AppTethering support System.Tether.Comm.pas System.Tether.Consts.pas System.Tether.Manager.pas System.Tether.NetworkAdapter.pas System.Tether.TCPProtocol.pas System.Threading.pas: this unit defines the Parallel Programming Library (or PPL) System.TimeSpan.pas System.Types.pas System.TypInfo.pas: the more traditional RTTI access System.UIConsts.pas System.UITypes.pas System.VarCmplx.pas: these units offer limited variants support System.VarConv.pas System.Variants.pas System.VarUtils.pas System.Zip.pas: compression support

164 System.ZLib.pas System.ZLibConst.pas Linux und Posix Units Posix.ArpaInet.pas Posix.Base.pas Posix.Dirent.pas Posix.Dlfcn.pas Posix.Errno.pas Posix.Fcntl.pas Posix.Fnmatch.pas Posix.Grp.pas Posix.Iconv.pas Posix.Langinfo.pas Posix.Limits.pas Posix.Locale.pas Posix.NetDB.pas Posix.NetIf.pas Posix.NetinetIcmp6.pas Posix.NetinetIn.pas Posix.NetinetIp6.pas Posix.NetinetTCP.pas Posix.NetinetUDP.pas Posix.Pthread.pas Posix.Pwd.pas Posix.Sched.pas Posix.Semaphore.pas Posix.Signal.pas Posix.StdDef.pas Posix.Stdio.pas Posix.Stdlib.pas Posix.String_.pas Posix.StrOpts.pas Posix.SysMman.pas Posix.SysSelect.pas Posix.SysSocket.pas Posix.SysStat.pas Posix.SysStatvfs.pas Posix.SysSysctl.pas Posix.SysTime.pas Posix.SysTimes.pas Posix.SysTypes.pas Posix.SysUio.pas Posix.SysUn.pas Posix.SysWait.pas Posix.Termios.pas Posix.Time.pas Posix.Unistd.pas

165 Posix.Utime.pas Posix.Wchar.pas Posix.Wctype.pas Posix.Wordexp.pas More units You can also use the Indy components, FireDAC, Dataspan, EMS, WebBroker and DunitX. In so far a quite extensive kit, with which one can work. Tip: With the use of FmXLinux (see almost all units are available as usual, with which you can also create desktop programs, eg. FMX.Forms, FMX.Dialogs, etc.

166 Chapter 6: Working with Graphics in FireMonkey 1. FireMonkey TBitmap versus Windows TBitmap The Windows bitmap and FireMonkey bitmap are different. This particularly concerns the pixel formats. While the Windows bitmap has, beside the 24- bitmap format, other bitmap formats available, some output formats in FireMonkey are missing. In particular, for 1-bit, 4-bit, 8-bit, 16-bit and 24-bit, no output format is available if you want to save the bitmap with the extension ".bmp". While you can read and write the property "PixelFormat" in Windows TBitmap, it is just as a reading property available in FireMonkey. There is a private "SetPixelFormat" procedure in the TBitmap class. You could perhaps make this available with a class helper function, but it probably it will not make much sense since FireMonkey always operates with a 32-bit bitmap internally. However, when using the formats that typically include an alpha-channel, e.g., the format "PNG" or "TIF", these relevant informations are also written to the image file. When loading an 8-bit bitmap file in BMP format, the colors are taken over correctly into the FireMonkey bitmap. But after saving the bitmap file, it is a 32- bit bitmap file. And, unfortunately, the informations will be lost if one loads a Windows 32- bitmap file with an alpha-channel into a FireMonkey bitmap. The values of the alpha channel will not be adopted. They all have the value of 255 (which stands for completely visible). I am not quite clear whether this is a bug. 2. TBitmapData instead of ScanLine for bitmap manipulation While you can process bitmaps in the VCL with the "ScanLine" function, it will be replaced by the TBitmapData record under FireMonkey, from Delphi XE3

167 on. This record is defined as follows: TBitmapData = record private FPixelFormat: TPixelFormat; public Data: Pointer; Pitch: Integer; property PixelFormat: TPixelFormat read FPixelFormat; function GetPixel(const X, Y: Integer): TAlphaColor; procedure SetPixel(const X, Y: Integer; const AColor: TAlphaColor); Before you can access the pixels, you must ask for the access to the bitmap with the function "MAP", with which, depending on the type of the access, this bitmap will be disabled for other processes. This contributes to the thread safety of bitmap editing. If you have finished editing the bitmap, you release the access with "UNMAP". The access type is determined by the TMapAccess, which is defined as follows: TMapAccess = (maread, mawrite, mareadwrite); For example, to manipulate a particular pixel in a bitmap, it looks, as a whole, like the following (assuming mybitmap is a global bitmap-variable): procedure TF_Main.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single); var vbitmapdata : TBitmapData; vpixelcolor : TAlphaColor; begin if MyBitmap.Map(TMapAccess.maWrite, vbitmapdata) then begin vbitmapdata.setpixel (Round (x), Round (y), TAlphaColors.Red); MxBitmap.Unmap(vBitMapData); If you also need a reading access, you must use "mareadwrite". If you need only read access, use "maread".

168 The example is simple and then easier to understand. But in your own projects, you should, of course, work with TRY... FINALLY constructs to ensure that the blocking of the bitmap will be cancelled in the case of a fault. 3. How to change the alpha channel of a TBitmap If you want to change only the alpha value of a pixel, you need to use a little trick. Use the TAlphaColorRec to get directly access to the byte which is responsible for the value of the alpha-channel. This works as follows: procedure TF_Main.SetAlpha(X,Y: Integer; AVal: Byte); var vbitmapdata : TBitmapData; vpixelcolor : TAlphaColor; begin if MyBitmap.Map(TMapAccess.maReadWrite, vbitmapdata) then begin vpixelcolor := vbitmapdata.getpixel (x, y); TAlphaColorRec(vPixelColor).A := AVal; vbitmapdata.setpixel (x, y, vpixelcolor); MxBitmap.Unmap(vBitMapData); 4. How to draw on the canvas of a bitmap As it is known from the Windows bitmap, it is also possible to draw on the canvas of a FireMonkey bitmap. You can use this as "Bitmap.canvas.Fillrect", "Bitmap.canvas.Fillelipse" etc. The well known "canvas.textout" function under Windows is not available here. Use the "canvas.filltext" instead. Finally a special note: You must call "Canvas.BeginScene" before all the drawing actions on the canvas and "Canvas.EndScene" after completion. So this would look like, for example, as follows: If Bitmap.canvas.beginscene then begin try

169 Bitmap.canvas.Filltext (...); finally Bitmap.canvas.EndScene; End; End; With Delphi 10.2, TBitmap, TCanvas and TContext 3D were made threadsafe. This means that bitmaps can be generated and used by several threads "simultaneously". This is done in that way, that the accesses are serialized internally (added into a queue). In fact, only one thread at a time has access to the resource at the same time, but you do not have to worry about it, because Delphi takes the work off you. An explicit synchronization as before, is therefore no longer necessary! Of course, a "logical synchronization" is still necessary. So you have to take care fore, that objects are not deleted by a thread, while there are still in read or write accesses. As a consequence of this innovation, you should keep access to the canvas in iterative loops as short as possible so that accesses are not blocked too long. Instead of as before: Canvas.BeginScene; try for I := 0 to do begin // thread code // drawing code finally Canvas.EndScene; your write now: for I := 0 to do begin // do "normal" thread work Canvas.BeginScene; try // do drawing code finally Canvas.EndScene;

170 5. How to turn graphics, flip, invert or color to gray A series of graphics processing functions are already available by default in FireMonkey. Want to rotate an image left or right? Nothing easier than that: Bitmap.rotate (270); // Turn bitmap left Bitmap.Rotate (90); // Turn bitmap right To mirror a graphic horizontally or vertically: Bitmap.Fliphorizontal; // mirroring the picture horizontal Bitmap.FlipVertical; // mirroring the picture vertical To invert an image or to change to gray color, you can use one of the most extensive filter functions supplied in FireMonkey. A nice example among the FireMonkey demos is the one that demonstrates what filters are available in FireMonkey. You will find it in the examples-folder in the subfolder "shader filter". Although the demo can demonstrate a lot, it's a pity that it written in a way that many functions are generated at runtime or dynamically. If we look into the source code, it is not very helpful unfortunately. I have, therefore, created a simple function which illustrates the use of filters. For example, to invert an existing bitmap, it is sufficient to call the function as follows: MyBitmap.Assign (ImgByFilter (MyBitmap, 'Invert')); And so looks the function (the unit "FMX.Filter" is required): function ImgByFilter(bm: TBitmap; FilterName: string): TBitmap; var bmold: TBitmap;

171 Filter: FMX.Filter.TFilter; begin Filter := TFilterManager.FilterByName(FilterName); bmold := TBitmap.Create (0,0); bmold.assign(bm); if Filter <> nil then begin // set input Filter.ValuesAsBitmap['Input'] := bmold; // set Target only for transition Filter.ValuesAsBitmap['Target'] := bm; // apply and get into result Result := TBitmap(Filter.ValuesAsBitmap['output']); Filter.Free; bmold.free; To change a bitmap into gray color, call the filter function as follows: Myitmap.Assign (ImgByFilter (MyBitmap, 'Monochrome')); Of course, with this function, only the filters are applied that work without additional settings. In the FireMonkey demo mentioned above, the use of filters with settings has been solved so that a filter attribute-record with the possible attribute-names and setting values of the filter will be filled at runtime. This information is used to generate dynamically TTrackbars that are generated with the minimum and maximum values of the filter attributes. This TTrackbars are also associated with an event handler to respond to changes in TTrackbars and then apply the filter to the bitmaps accordingly. This is also the reason why the demo is not so easy to understand when you look at the source code of the demo. You could extend the "ImgByFilter" function, for example, to integrate the following settings: Filter.ValuesAsPoint

172 Filter.ValuesAsColor Filter.ValuesAsFloat Filter.ValuesAsTexture For example, in order to apply the sepia-filter with a specific value you would - before calling the ValuesAsBitmap with the "output" option - use the following line in the above function before: Filter.ValuesAsFloat ['Amount'] := 0.2; Here you would get a 20% sepia-coloring of the bitmap. It should be noted, however, that not all settings are used with "Amount". Some use, for example, "Levels", "Length" or "Opacity" and the settings are not always between 0 and 1, they can have also other minimum and maximum values. To get this informations, the shader filter demo mentioned before can help you. There, you can simply click on the filter name and you will get the individual settings name and the value ranges will be shown. Here is an example of the "sharpening" function: And here is an example of the "Emboss" function which uses two setting attributes at the same time:

173 Overall I think, that the graphics capabilities of FireMonkey are quite impressive. 6. Hot to draw a bitmap scaled From the VCL, you know, for example, the "StretchDraw" function which allows you to draw scaled graphics. In FireMonkey, you can use the function "DrawBitmap". I use this, for example, also in my App Store program "MultiScreenCopy": So just assumed you have a bitmap in the TImage component "Bild" in the size of 1680x1050 pixels. It can be scaled, for example, as shown here, down to 1024x640 pixels (proportional). if ShowModal = mrok then begin bm := TBitmap.Create(StrToInt (cenewwidth.text), StrToInt (cenewheight.text)); bm.canvas.beginscene; bm.canvas.drawbitmap(bild.bitmap, RectF(0, 0, Bild.Bitmap.Width, Bild.Bitmap.Height),

174 RectF(0,0, StrToInt (cenewwidth.text), StrToInt (cenewheight.text)), 1, False); bm.canvas.endscene; End; So you first create the bitmap in the desired new size and then paint on the canvas with "DrawBitmap". You can use the original bitmap, its size and the new desired output size as a parameter. To define the transparency, you set it to "1" for fully visible, and the interpolation-mode ("HighSpeed" =) set to "False".

175 Chapter 7: 3D-Programming Section 1: Overview 1. 3D-Objects With 3D elements, you can display objects in 3D space. This is achieved by adding the value "Depth" for the 3D objects (TSphere, TCube, TCone, and so on) next to the value for "Width" and "Height". A special feature applies to (normally) flat 2D objects in 3D space, such as TImage3D and TTextlayer3D. There is a hard-coded value for the depth, namely 0.01, so there is also no adjustable property for "Depth". In addition, there is also the value "Position.z" for the position next to "Position.x" and "Position.y", which indicates the spatial arrangement forwards or backwards. Increasing positive Z values means that the object is moved further backwards into the space, so the object is reduced in size as viewed from the front. Negative Z values bring it closer to the foreground, so it is viewed from the front, larger. The spatial impression is also generated by a changeable viewing direction. This can be achieved e.g. with a TCamera component from which you can have one or more on your form, so you can switch the direction of view. 2. Cameras Each view of the 3D space is controlled by a camera. The position and orientation (3D rotation) of the camera determines what you see. Each 3D form already has an integrated camera (design camera) which is activated by the "UsingDesignCamera" property by default. It is used in the Form Designer and by default at runtime. A 2D form does not have this property, thus not a standard camera. In 2D forms, you display 3D elements within a 3D ViewPort, and this component also has the "UsingDesignCamera" property. In either case, you can disable this option and

176 add one or more custom camera components. 3. Screen Projection By default, the Projection setting for each 3D object is set to "Camera". Therefore, if the camera position change, the 3D object will be possibly out of view. With a setting "Screen" for projection, you can ensure that objects remain in the view regardless of the camera view (for example, position information or other status information). Attention: If you change this setting to "Screen", the values of units changes to pixels. Then, the upper left corner becomes again the zero point, but the 3D position still indicates the center of the object, not its upper left corner as in 3D: Here you see: Although the object is in the upper left-hand side, the values X and Y are not zero because, as I said, the center of the object still determines the values for X and Y. 4. Rotations A spatial impression can also be produced by turning the objects. You can use the individual values RotationAngle.x and RotationAngle.y. For example, if you have a cube (TCube), you can rotate it horizontally around its own axis by changing the RotationAngle.Y value. Up and down view will not change, but you see, if you change the values with a TrackBar from 0 to 360, with one turnaround 4 pages, from right to left. The same thing is done with RotationAngle.X, then the cube makes forward roles, it rotates from top to bottom. 5. Light Of course, the light also plays a part in creating a special view. With the TLight component, you can illuminate objects (which are connected to a TLightMaterialsource) differently. The light emits white by default, but you can also change it using the Color property. There are also 3 different light types. The best way to understand the effects of the different light types (LightType property) is to have several objects in the room. In the following we have the

177 description of the different light types and screenshots for the respective result: Directional Directional light is constant from a given angle. Important is the direction in which the light appears, which is defined by its RotationAngle and the RotationAngle of the parent object. The following figure shows that all objects are illuminated from the same direction and distance: Point Spot light is comparable to the light of a light bulb. It radiates in all directions and decreases with the distance. The value of the RotationAngle has no effect. His position, which is influenced by the position and rotation of his parent objects, is important. The closer the object, the greater the point of irradiation, the farther away, the more diffuse the effect: Spot Spotlight is dependent on position and rotation and decreases with distance. Thus, the orientation of the light source is of the greatest importance. Objects

178 that are outside the light cone are not irradiated, here the right-hand cube: With the Spot setting, the two "SpotCutOff" and "SpotExponent" properties still have an effect on the light. Just experiment a little by modifying the default values. Tip: Turn the light off by setting enabled to false, you'll immediately see the difference. 6. Materials The surface of a 3D object is determined by its material. You can use the "MaterialSource" property to assign different surface types to the 3D object: ColorMaterialSource The simplest "material" consists of a simple color. Color transitions are not possible. TTextureMaterialSource You can create any 3D object with a texture, that means cover the surface with an image. Depending on the 3D object being used, it is important whether the texture appears "seamless", that means without a visible transition. There are image processing programs which can calculate such things for graphics, e.g. the FilterForge program. Instead of using a fixed graphic, the texture can also be generated as a bitmap animation, so the transition from one graphic to the other. TLightMaterialSource Here too, the surface is given a color, but it is appearance depended from the

179 light with witch the color is irradiated. Three different settings are relevant: Ambient: Specifies the visible base color for surfaces. In the real world, light is reflected from many directions onto a surface; but in the 3D scene, it would be extremely difficult to define all of this light. Therefore, the surrounding color is activated by any light in the room (without light it has no effect.) The surface is displayed completely uniformly in this color. With directional light - which does not have to be directed to the surface - everything would look flat. With spotlight the colors become weaker with distance. Emissive: This color determines whether a surface emits its own light or is illuminated. The default is zero (no visibility): objects do not normally light up and require light to be seen. By setting a color, surfaces appear without light in this color. Diffuse: This color interacts directly with light and with the incidence angle of the light. Without light it has no effect. It is common to set Ambient and Diffuse to the same color. Specular: This color simulates a glossy surface by reflecting incident light at a specific angle, instead of diffusing light in many angles. With no light, Specular has no effect. It defaults to white to reflect the light without altering its color. Note: Extruded objects (such as TText3D) have the additional properties "MaterialShaftSource" and "MaterialBackSource". TMaterialBook You can load several materials into a TMaterialBook, which is then used as a material library. Example: var Form26: TForm26; mabook: TMaterialBook; implementation {$R *.fmx}

180 procedure TForm26.Button1Click(Sender: TObject); begin cube1.materialsource := mabook.materials[1]; Viewport3D1.Repaint; procedure TForm26.FormCreate(Sender: TObject); begin mabook := TMaterialbook.Create(self); // Material 0 mabook.addobject(colormaterialsource1); // Material 1 mabook.addobject(lightmaterialsource1);

181 Section 2: The 3D Coordinate System One of the difficulties with the introduction of 3D programming with FireMonkey is that you have to get used to a different and extended coordinate system. While in 2D programs, the zero point is at the top left of the form (as in the VCL system), the zero point is located in a 3D form or in a Viewport3D with the projection "Camera" exactly in the middle, both horizontally, vertically and in the depth. Here is a screenshot, where I inserted a Viewport3D in a 2D form. The Viewport3D contains a 3D-object (TCube). At the same time I inserted the 2Dobject TRectangle, which is not in, but over the ViewPort3D element (so parent of the TRectangle is the form). Both objects - TRectangle and TCube have the value 0,0, or 0,0,0: In the 2D world you specify height and width in pixels, in the 3D world (projection=camera) in units. Optically, both objects have the same width, the rectangle has 63 pixels for Width and Height, and the TCube object has a Width, Height, and Depth value of 4, respectively. It is also interesting when you change the size of an object, which is located in the 2D world on the surface or in the 3D world in space, in the width and height:

182 In the 2D world, the object grows to the right and down, while in the 3D world, the change in size effects uniformly in all directions. In the next picture, I have enlarged the object in the width, compare the starting positions and the end positions: As you can see, the 3D object has expanded evenly to the left and right, while the 2D object has only expanded to the right. The value for RotationCenter also has different meanings in 2D and 3D: For 2D objects the variables X and Y can have a value between zero and one, the rotation center point is therefore 0.5 for X and also 0.5 for Y. In the following graph, the single "x" under the horizontal line indicates the center of rotation:

183 With a value of 0,0 for "RotationCenter" the rotation would have its center point at the top left of the component. For 3D objects, the value is set initial to 0,0,0. You can not change this at the design time, only at runtime (!). In the following picture you can clearly see the center of rotation exactly in the center of the 3D object: Here it is also worthwhile to look at the corresponding demo program, that I have developed, in order to see the different points in the 3D space. At the design time the program looks like this:

184 At runtime, you can remove or add individual surfaces from the cube and rotate the entire object in the room and view it from different perspectives. The program is impressive, because it was created purely with visual live bindings, there is no single line program code. Note: If you run the program in a virtual machine (here: Linux as host, Windows 10 as Client, with "VirtualBox"), the text3d elements are not displayed correctly. This is not a program error but it is a result of running in the virtual machine. Here you can download the program:

185 Section 3: 3D-Application "Atomic Model" When you create a new "multi device application", you have only one option that creates a "real" 3D application: Only the "3D Application" selection creates an application with the form "TForm3D" (instead of TForm). Although you have basically two possibilities to accommodate 3D elements in your program: The real 3D application Here you can directly insert the desired 3D objects (for example, TCube, TLight, etc.) into the form. If you need 2D-controls in the program interface (e.g. buttons), use a "TLayer3D", preferably with the projection "Screen", then you can also use the Align property of the "TLayer3D". The normal application with 3D elements In a normal application (formerly called HD application), you can add 3D objects to the program through a TViewPort3D component. However, in the two approaches, we have significant differences in speed. If you use complex animations with movements of illuminated objects in your program, you can quickly reach performance limits, i.e. jerks in the display, via the HD application with 3D elements. You should therefore first consider what your program should do. In the "Solar- Model" demonstration program discussed here in the book, where several planets are rotating in the solar system, the speed in the real 3D application is OK, the HD application with 3D elements would lead to jerks.

186 Demoprogram "Atomic Model" Here, we will first create an animated water molecule using 3D objects and LiveBindings only. The result looks like this and can be rotated on different axes: Now we create the program step by step: 1. Create a new 3D application 2. Insert a TLayer3D element, select "Screen" under the property "Projection" and set the width to 150 pixels and "Align" to "Right". 3. Insert a TDummy object. 4. In the TDummy object, insert a TSphere (Sphere1). Set the values for Position.x to -3.5 and Position.y to Add another TSphere object (Sphere2) to the TDummy object and set the values for Position.x or Position.Y to 3.5 and 3 respectively. 6. Paste the last TSphere object (Sphere3) and leave it at the insertion position (0,0,0). 7. For all TSphere objects, set the Width, Height, and Depth values to "3" to

187 get a larger round ball. 8. Now insert a TCylinder object into the TDummy object and set the values for position.x to -1.5 and for position.y to 1.5. Set Depth to 0.2 for Width and 0.2 for Height, and 6 for Height. Finally, set RotationAngle to 52 (the two hydrogen atoms are at an angle of about 104 degrees to each other, with 52 we have the left wing). 9. Now insert another TCylinder object into the TDummy and set the values for Position.x and Position.y to 1.5. Set the values for Width, Height and Depth as in No.8, only the value for RotationAngle you set to Now add 3 TLightMaterialSource, for the values Ambient you set "Red", "Darkblue" and "Gray", for the "Diffuse" value "WhiteSmoke". 11. In Sphere3 for "MaterialSource" you assign the component LightMaterialsource1 (Red), for Sphere1 and 2 you assign LightMaterialSource2 (Darkblue) to "MaterialSource". 12. In order for the objects to be illuminated, we add a TLight object and position it in the upper left corner. If you now run the program, you will see the Atom model, but still immobile. 13. We bring the movement into the project with 4 float animations. Set the FloatAnmiation1 values as shown in the screenshots below:

188 For FloatAnimation2, set it just the same, but select "RotationAngle.Y" for PropertyName, and for Enabled, select "True". For FloatAnimation3, set the values as well, but for "PropertyName", "RotationAngle.Z" and set Enabled to False. For FloatAnimation4, set the values as shown below:

189 14. Now add 4 TSwitches and 4 TLabels into the TLayer3D and name the text properties, as shown in the first screenshot above. 15. Now click on the TDummy object with the right mouse button and select the "Visually Binding" command. The LiveBindings Designer opens, where you create the links as follows: Note: If some objects should not be displayed here, click on the object in the structure view and select the "Visually Binding..." command. You can display the individual properties here in the boxes by clicking on the 3 small dots and selecting the required properties in the dialog that appears. You then click on a value (for example, IsChecked) with the left mouse button and, while holding down the mouse, drag the connection to "Enabled". This completes the program and you can run it. Note that it does not need a single line source code. How does it work now? The LightMaterialSources give the 3D objects a surface, which reflects the light according to the effect of light.

190 The values "StartValue" and "StopValue" in the FloatAnimations ensure that the TDummy object rotates around its own axis with all the contained objects (X, or Y axis, with values from 0 to 360), forward or rear (Z-axis, with values from 30 to 0). The respective animations are activated by the switches (TSwitch), depending on whether enabled = True or False. Another tip: If you set the Spheres values to "SubdivisionsAxes" or "SubdivisionsHeight" to 45, the spheres have a smoother effect on the curves, which is particularly noticeable when you enlarge the shape. Here you can download the demo:

191 Section 4: 3D-Application "Solar Model" The next 3D application is a solar model, where the ways of our planets around the sun is simulated. Also, this is an impressive example of what you can do with FireMonkey for effects without creating a single line of code. Here is a screenshot of the application: At runtime, the individual planets rotate around the sun at different speeds, in relation to their actual orbital period around the sun. I will not give you a step-by-step guide, but explain some basic things. On YouTube there is also (in the near) a small video, that one can look at it additionally. The structural overview of the program provides an overview of the design:

192 The sun does not move and is in the center. It consists of the 3D object "TSphere", as well as the planets. Directly in the middle of the sun is the Light1 (TLight) placed, thus the light source. The light type is "point", therefore the light radiates uniformly in all directions. The object "DummySpace" is a TDummy object, which contains the other 3D objects. This DummySpace object can then also be changed with the two sliders (in size and in position). But the most important are the respective planets. They each consist of a dummy object that contains a TSphere, a TFloatAnimation, and a Path3D object: The Path3D3 object symbolizes the path data (the way which the object has to take), here the DummyEarth object (visible is the "searth" object). The FloatAnimation is linked to the value "RotationAngle.Y" of the DummyEarth object via the property "PropertyName". For StartValue, the value

193 is equal to zero and for StopValue is equal to 360. The object moves in the circle. The "duration" stands at 36.5 seconds, which should correspond to the 365 days of a year. Venus needs only 225 days to circumnavigate the sun, so the FloatAnimation of Venus has got the value The other values correspond to the respective relative orbital times. For interested parties here the exact values: Mercury: 88 Tage Venus: 225 Tage Earth: 365 Tage Mars: 687 Tage Jupiter 4329 Tage Saturn: Tage Uranus: Tage Neptun: Tage The planets Uranus and Neptune I have not included in the animation, because of the long round times one would have to wait some time until you see the animation. The size of the planets and the distances to each other and to the sun are not true to scale, since otherwise things could not be so clearly displayed. I created the orbits of the planets (circles) with a Tpath3D object, placed centrally in the middle and each took a different width and depth to get different dimensions and distances. The data for the circle I created with my image processing program PixPower, which can generate SVG data from the painted objects:

194 The SVG data generated in this way can then be copied to the clipboard in PixPower and inserted into the Tpath3D object using the "Path, PathData" property. Here you can download the demo program:

195 Chapter 8: Animations, Transitions and Effects FloatAnimations have already been used for various demos in the book ("Atomic Model" and "Solar Model"). Besides the FloatAnimation, the TColorAnimation is also interesting. This allows you to change a color to a different color in a desired time period. Here is a small demo, which is supposed to simulate a laboratory experiment, where a blue liquid changes into a yellow liquid in a test tube. This demonstration project shows at the same time, with how little effort you can achieve interesting results. This is how the project looks in Design mode: In the structure overview, you can see how the objects have been constructed:

196 The test tubes consist of a simple combination of rectangles and ellipses. The colored liquid consists of 2 ellipses and a rectangle, the rectangle has for opacity the value of 0.9, so that it is a little bit transparent and you can almost see the back edge of the ground. With two TShadowEffect components inserted into the two lower ellipses, the test tube throws a slight shadow to the ground. These are very simple but also impressive constructions. With a little imagination and creativity you have almost endless possibilities. The required program code for the program is quite short: procedure TForm11.bnStartAnimationClick(Sender: TObject); begin ColorAnimation1.Enabled := false; ColorAnimation1.Enabled := true; procedure TForm11.ColorAnimation1Process(Sender: TObject); begin EllipseTop.Fill.Color := Rectangle2.Fill.Color; EllipseBottom.Fill.Color := Rectangle2.Fill.Color; With ColorAnimation.enabled = True the animation will be started (reset with False). Since the ColorAnimation can only be bound to one object, we use the

197 "ColorAnimation1Process" event to adjust the lower and upper ellipse of the color liquid with the Rectangle element. At runtime and after clicking on start, after 2 seconds ("duration" of the ColorAnimation has this value) the result looks like in the picture below, whereby, of course, a smooth transition is to be seen: A similar animation as the TColorAnimation represents the TGradientAnimation, except that we have not a whole area simultaneously changing its color, but a change of the color gradient. We do not use the property "Fill.Color" but "Fill.Gradient". So if you are using a TRectangle, for example and you want to achieve a pulsating color, you must first set for "Fill", the property "Kind" to "Gradient", because the default is "Color". There are other animations:

198 To go into all of them in detail would go beyond the scope of the book. Therefore, I will give only a brief description of the animation types that have not yet been discussed, and hints where you can find more information: TRectAnimation: This is used to change animated the edges of an object (for example, TRectangle), which is per Align = client in another object. More info: TBitmapAnimation: When you insert it into a TImage, you can display a transition from one image to another. As PropertyName, use "Bitmap". More info: TBitmapListAnimation: Animate a single bitmap by dividing it into frames and displaying the frames successively, like a timed clip. More info: TColorkeyAnimation: Transitions through a list of colors. Similar to TColorAnimation, but one can create different "ColorKeys" (property "Keys"), which should be used for the transitions. TPathAnimation: Changes the 2D position of an object according to a TPath with optional rotation along the path.

199 Chapter 9: Sending and receiving messages with the TMessageManager From Windows, you know the API functions "SendMessage" and "PostMessage", which can be used to send messages program wide or system wide. You could use these functions also on Windows with FireMonkey, but under MAC OS or on other platforms, they would not work. Therefore Delphi brings with the RTL its own message solution, the TMessageManager from the unit "System.Messaging". This unit must always be included if the MessageManager is to be used. At first you must decide to use your own MessageManager (which you derive from TMessageManager) or the default MessageManager ("TMessageManager.DefaultManager"). The latter is always available, so it does not have to be generated separately or released to the end of the program. However, you can save a little bit of typewriting by declaring a global variable "MessageManager" of the type "TMessageManager" to which you assign the DefaultManager at program start: var MessageManager: TMessageManager; begin MessageManager := TMessageManager.DefaultManager; In many cases, it will be best to specify the types of messages you want to be notified directly from the program start. This is like on the Internet with the newsletters, you subscribe or unsubscribe. In the following are two demos to show the actual usage.

200 Section 1: Simple Messaging-Demo As a finished program, the demo looks at runtime as follows: Here you can see that the text "Eine Textinfo" has been sent to the program and there is an instance (a "listener") that responds to it and shows the received text. The source code for the program is very short, since both the standard MessageManager and a standard message type were used here: procedure TF_Main.bnSendClick(Sender: TObject); begin With TMessageManager.DefaultManager do begin SendMessage(Sender, TMessage <UnicodeString>.Create(Edit1.Text)); procedure TF_Main.FormCreate(Sender: TObject); begin With TMessageManager.DefaultManager do begin SubscribeToMessage(TMessage<UnicodeString>, procedure (const Sender: TObject; const M: TMessage) begin ShowMessage ('Message of kind "TMessage <UnicodeString>" received:' + #13#13+ (M as TMessage<UnicodeString>).Value); end);

201 Let us first look at the function "SubscribeToMessage". This is from the Unit "System.Messaging" and looks like this in the declaration: function TMessageManager.SubscribeToMessage( const AMessageClass: TClass; const AListenerMethod: TMessageListenerMethod): Integer; A TMessage class is expected as the first parameter. This can be a class you have created, and is derived from TMessage (I will go into this later in the second example). Or it can be an existing "class", in this case "TMessage <UnicodeString>. In the second parameter, a "Listener-Method" is expected. This is of type "TMessageListenerMethod" and is simply a procedure of object: TMessageListenerMethod = procedure (const Sender: TObject; const M: TMessage) of object; The second parameter therefore looks like this: procedure (const Sender: TObject; const M: TMessage) begin // Do what you want here with // (M as TMessage<UnicodeString>).Value); end); The MessageManager will always call this listener method when it receives this type of message. Within this listener method, you can then do what you want with the information. You also have full access to your form and its components within this method. So you can paste this text into a list box or whatever else you want to do with it. Sending the text message is simple and always works according to the pattern: MessageManager.SendMessage(Sender:TObject, Message: TMessage); That means like this:: SendMessage(Sender, TMessage <UnicodeString>.Create(Edit1.Text));

202 In this case, "Sender" is simply the button that was clicked, and a Unicode string with the contents of Edit1.Text is created as a TMessage object. The thing is more interesting if we pass not only a string, but a component, e.g. a Listbox, a StringGrid or whatever else, so that you have than full access to their properties and the recipient of the message can evaluate this state and can react to specific states if necessary. We will look at an extended possibility in the second example.

203 Section 2: Enhanced Messaging-Demo In this example, we use our own MessageManager and our own TMessage classes. In the finished program, you can send a text that is received and processed by different listeners (each added text to a listbox). In addition, it can also be sent as information that a selection has changed in a list box (ItemIndex changed). The listeners are set up (subscribe) at runtime by the user and, if necessary, they can be uncoupled (unsubscribe) later from the MessageManager. At runtime, the program looks like this (after pressing the upper and lower Subscribe button, text was sent twice and different entries were clicked in the upper listbox): First, let's see what happens when the "Subscribe 1 Msg" button is pressed: procedure TF_Main.bnSubscribeToTxtMsgClick(Sender: TObject); var TextMessageListener : TMessageListener; begin TextMessageListener := procedure(const Sender: TObject; const M: TMessage) begin

204 ListBox1.Items.Add('TTextMessage Received. Text = ' + (M as TTextMessage).Text); fsubscriberid1 := MessageManager.SubscribeToMessage(TTextMessage, TextMessageListener); Here, a listener method is first declared, which can then be used as the second parameter in the SubscribeToMessage function. I have separated this method for the sake of better readability, but you can of course do everything in one step, as shown below, when further listener methods are declared and passed to the MessageManager. But first a few words about the used TMessage object. It is of type TTextMessage, which we declared as a class: TTextMessage = class(tmessage) private ftext: string; public property Text : string read ftext; constructor Create(const Text : string); virtual; The variable "fsubscriberid1" is declared as an integer in the private section and is required later e.g. to use the unsubscribe function (with this ID we can then identify us). Here is the setup of two other listener methods: procedure TF_Main.bnSubscribeMsg2Click(Sender: TObject); begin fsubscriberid2 := MessageManager.SubscribeToMessage (TTextMessage, procedure(const Sender : TObject; const M : TMessage) begin ListBox2.Items.Add('TTextMessage Received. Text = ' + (M as TTextMessage).Text); end); fsubscriberid3 := MessageManager.SubscribeToMessage (TListboxIndexChangedMessage, procedure(const Sender : TObject; const M :

205 TMessage) begin ListBox2.Items.Add ('TListboxIndexChangedMessage Received. Item = ' +IntToStr((M as TListboxIndexChangedMessage). Listbox.Selected.Index)); end); Again a listener method is created that responds to the sent text. Additionally, a listener method is created that responds when the value of the ItemIndex changes to Listbox1. The message type was created by us as follows: TListboxIndexChangedMessage = class(tmessage) private flistbox: TListbox; public property Listbox : TListbox read flistbox; constructor Create(const Listbox : TListbox); virtual; Where is the source code, where we can see how the relevant messages are sent? First of all the sending of the text message: procedure TF_Main.bnSendTextClick(Sender: TObject); begin MessageManager.SendMessage(self, TTextMessage.Create(EdTxtToSend.Text)); And here the sending of the information that the ItemIndex of Listbox1 has changed: procedure TF_Main.ListBox1Change(Sender: TObject); begin if cbpublishselchange.ischecked then MessageManager.SendMessage(self, TListboxIndexChangedMessage.Create(ListBox1)); The "ListBox1" is specified in the TListboxIndexChangedMessage.Create as parameter. Thus, the recipient of this information obtains full access to the ListBox1 and can retrieve all required information.

206 If we want to remove the listener methods from the notification later, we use the Unsubscribe function together with the previously noted ID: procedure TF_Main.bnUnsubcribeFromTxtMsgClick(Sender: TObject); begin MessageManager.Unsubscribe(TTextMessage, fsubscriberid1); procedure TF_Main.bnUnsubscribeMsg2Click(Sender: TObject); begin MessageManager.Unsubscribe(TTextMessage, fsubscriberid2); MessageManager.Unsubscribe( TListboxIndexChangedMessage, fsubscriberid3); This gives you a very flexible way to send messages and this works on all platforms supported by Delphi. For example, in your program has several open forms that need to respond to certain changes in the main form, then send a message and all forms that have previously been subscribed to receive this message receive this info and can respond accordingly. The potential for using this technique in applications are manifold. Also, in the context of reducing the necessary references of units to other units, messages can be a help. Let's take the case that the results of different database queries should be displayed in several different non-modal windows. With the closing of the database we wish that all the corresponding information windows should also be closed. To do this, simply send a text message with the content "CloseQueryDisplayWindow" and all windows that have subscribed for receiving text messages can respond to this message if it is relevant to them. You could make the following entry in the FormCreate event of the DisplayForm:

207 with TMessageManager.DefaultManager do begin SubscribeToMessage(TMessage<UnicodeString>, procedure(const Sender: TObject; const M: TMessage) begin if (M as TMessage<UnicodeString>).Value = 'CloseQueryDisplayWindow' then self.close; end); And if you then send the following in a suitable place in your program: with TMessageManager.DefaultManager do begin SendMessage(sender, TMessage<UnicodeString>.Create ('CloseQueryDisplayWindow')); all instances of the generated display forms will be closed. This approach is quite practical in so far, that you do not have to manage the generated display-forms in a list and it can also be forms of different types, which are subscribed for the receipt of this message.

208 Chapter 5: Useful third-party components for FireMonkey 1. TMS-Components The TMS components have already been mentioned several times in this book. The TTMSFMXGrid provides a number of useful features, e.g., in the combination with the possibility to export the content of the grid as Excel, RTF or PDF file (TTMSFMXGridExcelIO, TTMSFMXGridRTFIO, TTMSFMXGridPDFIO). The TTMSFMXRichEditor which is a worthy replacement for the VCL RichEdit component was also briefly mentioned. With the TTMSFMXRichEditorFormatToolbar component and the TTMSFMXRichEditorEditToolbar two ready to use toolbar components are delivered, which you can combine with the editor. The TMS-Rich Editor can save, if necessary, his text as a RTF or HTML file. For the Rich Editor, I have placed a short video on YouTube. Just have a look here: Good news: From the version of TMS Pack for FireMonkey on, one can even attach a complete spell check to the Rich Editor. The dictionaries are provided, inter alia, in German, English, French, Spanish and Italian. Here is the link to the TMS Pack for FireMonkey: Finally, I will mention here the TMS cloud Pack for FireMonkey: With that you will get access under Windows, MAC, ios and Android to the various cloud services, which are offered for those platforms. For instance, DropBox, Google

209 Drive, Windows OneDrive BOX and services on ios. Here is the link to the TMS Cloud Pack for FireMonkey: Even when you want to or must use certain native components for the MAC (or ios), TMS can help you with the mcl components (or icl on ios). In a cross compile project, however, you have a bit more work in using of this components, because, of course, the native MAC OS components will not work for the Windows Desktop. But, sometimes, it's the only way to realize a project for the MAC at all. For example, to display PDF files in a separate form in my invoice program on the MAC, I use the TMSFMXNativeNSView component from TMS (while I use a with a Hydra-module integrated component of Gnostice under Windows). The direct generation of PDF invoice file I'll do on the MAC with the TMSFMXNativeMacPDFLib component. Here is the link to the TMS mcl components: However, TMS has more FireMonkey components to offer. A complete overview of the TMS Components for FireMonkey can be found here: 2. Report-generator: FastReport FMX With Fast Reports FMX, you can create reports like you used to do it under the Windows VCL. In Delphi 10, although a standard version of Fast Reports FMX is included, it contains a no re-distributable report- designer. This is obtained when one acquires the commercial version of Fast Reports. Here is the FastReport designer at design time:

210 These components provide a large amount of options for creating reports (incl. PDF output). Here is the link: 3. RemObjects-Application Framework (Hydra) Hydra are not components, but is a framework that allows you to mix VCL and FMX components in one form. For example, you can directly integrate FMX components in a VCL Forms (or vice versa). This is surely a way that should not be the focus of your work with FireMonkey. But it offers additional ways and opportunities to pick all possibilities from the VCL and FMX worlds out. Here is the direct link: Here, too, I deposited a short video on YouTube. Take a view as you like: 4. Other components

211 Other component manufacturers have announced to support FireMonkey (e.g., Gnostice) or to wait a bit for a decision (DevExpress, ImageEn, TRichView). But there are also other developers and FMX supporters, who have developed a set of components and provide you them predominantly free of charge. Here I recommend you to take a look at and to examine whether there is something you need here (where most components rather refer to ios or Android development). You can also click at the Delphi start page on the "Get Add-ons from GetIt" and here, search for FMX:

212 Chapter 11: How to - tips & tricks for FMX Here you will find a number of different questions and answers. As a tribute to my beloved "cookbook" - the Delphi series by Walter Doberenz and Thomas Kowaslki - I follow the "recipes" (in German it means a kind of written description to handle something) from these books, using the R-numbering. R1... Get the display resolution? For this purpose, we used a platform service. Example: procedure Tfrm_Main.FormCreate(Sender: TObject); var ScreenSvc: IFMXScreenService; Size: TPointF; begin if TPlatformServices.Current.SupportsPlatformService (IFMXScreenService, IInterface(ScreenSvc)) then begin Size := ScreenSvc.GetScreenSize; Size.x give us the width and the height is in Size.y. In the meantime, this is much easier, since Delphi 10 Seattle has multi-display support, which can be accessed via the global screen variable (TScreen.Screen). Screen.DisplayCount gives you the number of monitors which you can then query via ScreenDisplays [x] for individual properties (width, height, WorkAreaRect, etc.). Here you can find more details:

213 R2... Check whether the Escape, Ctrl or Alt key is pressed Sometimes you need an offer to interrupt or cancel an ongoing process. In the VCL, under Windows, it works like this: if (Getkeystate (VK_CONTROL) < 0) then begin // Is the Shift-key pressed? // yes --> exit; And you do it so under FireMonkey: {$IFDEF MACOS} Uses MacApi.AppKit, MacApi.Foundation, Macapi.CocoaTypes; {$ENDIF} function IsControlKeyPressed: Boolean; begin Result := NSControlKeyMask and TNSEvent.OCClass.modifierFlags = NSControlKeyMask; In a Cross-platform way, you handle it like this at best: function IsControlKeyPressed: Boolean; begin {$IFDEF MSWINDOWS} Result := GetKeyState(VK_CONTROL) < 0; {$ELSE} Result := NSControlKeyMask and TNSEvent.OCClass.modifierFlags = NSControlKeyMask; {$ENDIF} function IsShiftKeyPressed: Boolean; begin {$IFDEF MSWINDOWS} Result := GetKeyState(VK_SHIFT) < 0; {$ELSE} Result := NSShiftKeyMask and

214 TNSEvent.OCClass.modifierFlags = NSShiftKeyMask; {$ENDIF} function IsESCKeyPressed: Boolean; begin {$IFDEF MSWINDOWS} Result := GetKeyState(VK_Escape) < 0; {$ELSE} // Result := NSEscapeKeyMask and // TNSEvent.OCClass.modifierFlags = // NSEscapeKeyMask; (so it does not work) {$ENDIF} What I still don't know is how to query the ESC key on the MAC. Please share it with me if anyone knows the solution. R3... Use folder names under Windows and MAC properly Under Windows, you use the "\" character to specify directories and files in a file path, e.g.: "D:\Data\Forms\File.doc". Under MAC, it is the "/" character which is to be used. Example: "/Users/harrystahl/Documents/Datei.doc". In order to make sure, that you always use the right delimiter, use the defined constant "PathDelim". Depending on whether you compile on Windows or Mac, the correct version is used. The excerpt from the unit "System.SysUtils" below shows, that also the constants "DriveDelim" and "PathSep" are available: const PathDelim = {$IFDEF MSWINDOWS} '\'; {$ELSE} '/'; {$ENDIF} DriveDelim = {$IFDEF MSWINDOWS} ':'; {$ELSE} ''; {$ENDIF} PathSep = {$IFDEF MSWINDOWS} ';'; {$ELSE} ':'; {$ENDIF} Thus, the root directory always starts with "/" under the MAC. If you want to find associated drives on the MAC, you must query the entries of the first-level

215 directory under "/Volumes". The following source code reads in the existing drives ("volumes") on my MAC (under Windows, it doesn't work like this, of course): // Units System.IOUtils und System.Types will be needed procedure TForm9.FormCreate(Sender: TObject); var sdadrives: TStringDynArray; sdrive: string; begin sdadrives := TDirectory.GetDirectories('/Volumes'); for sdrive in sdadrives do begin Listbox1.Items.Add(sDrive); Here are the results: Note: with "Add (copy (sdrive, 10, 255))", you would get only the drive name. On Linux, the drives are usually mounted under "media" and there under the current user account. Here, the following query would lead to a result: procedure TForm1.Button1Click(Sender: TObject);

216 var sdadrives: TStringDynArray; sdrive: string; begin sdadrives := TDirectory.GetDirectories('/media/' + ExtractFileName (GetHomePath)); for sdrive in sdadrives do begin Listbox1.Items.Add(sDrive); R4... Use search-mask for "all files" in Windows and MAC OS X properly If you want to view "all files" in file searches under Windows you use the mask "*.*". Under MAC, it seems also to work well. However, the right mask is "*". The mask "*.*" would not display files, that are without a file extension. I, therefore, use the following solution with a constant, which always has the right content in the used context: {$IFDEF MSWINDOWS} const AllMask = '*.*'; {$ENDIF} {$IFDEF MACOS} const AllMask = '*'; {$ENDIF}

217 R5... Avoid looping symlink folders (Alias) On the MAC, you can create an "alias" for folders and files. An alias folder is only a reference to the folder that is on another location on the hard drive. If you make a recursive search for files in a folder, including subfolders, you can possibly get an endless loop situation. If an alias in a folder "A" points to a folder "C" and a reference back to the folder "A" is found in this folder, the search will continue endlessly. Therefore, in a recursive file search the attribute "fasymlink" has to be filtered out. Here is an example of searching for all the ".pas" files in the folder "D:\Delphi" and storing the result in a TStringList : // Finds all files that match the specified criteria procedure FindThisFiles (pa: String; subdirs: Boolean; sl: TSTringList); var Search : TSearchRec; begin if FindFirst (Pa, faanyfile-fadirectory, Search) = 0 then repeat sl.add (ExtractFilepath (pa) + Search.name); until FindNext (Search) <> 0; FindClose (Search); if SubDirs then begin if FindFirst (ExtractFilePath (pa) + '*', fadirectoryfasymlink, Search)=0 then begin Repeat if ((search.attr and fadirectory)=fadirectory) and (search.name[1]<>'.') then begin FindThisFiles (ExtractFilePath (pa) + Search.Name+ PathDelim + ExtractFileName (pa), SubDirs, sl); until FindNext (Search) <> 0; FindClose (Search);

218 procedure TForm11.Button1Click(Sender: TObject); var sl: TSTringList; begin sl := TStringList.Create; FindThisfiles ('D:\Delphi\*.pas', true, sl); R6... In which situations file symlinks functions play a role otherwise If you want to get the attributes from a file you use "TFile.GetAttributes" Attributes: = TFile.GetAttributes ('MyFileName'); But it may be that the file is an alias. By default, you will receive not the attributes of the alias file, but the attributes of the file to which the alias file points (target file). You can use "TFile.GetAttributes", therefore, by adding another parameter (which, if not specified, is just true) in order to avoid the pointing to the target file: Attributes: = TFile.GetAttributes ('MyFileName', false); The function is declared in "System.Ioutils" as follows: class function GetAttributes (const Path: string; FollowLink: Boolean = true): TFileAttributes; inline; static; The FollowLink parameter also exist in a number of other file functions such "TFile.exists", "TDirectory.Exists", etc. When using file functions, you should always let show the parameters that you can use there because there are possibly even more than you would expect. Unchecked symlink properties can lead to unwanted results. Let's say you want to copy a file. If it is an alias, you do not copy the alias file with perhaps only 30 bytes, but the target file that is possibly several gigabytes in size. This can ever lead to surprises when you, for example, perform a backup of files in a directory. You should, therefore, always check files and test whether it is an alias file, and

219 then react to it as needed. Normally it should be sufficient to examine the attribute "fasymlink" in the file attributes. However, I've found, under the MAC, that some files here (for whatever reason) have the attribute although there are obviously no alias files. Just to be on the safe side, you could use the following example to check this: Function IsASymlinkfile (Filename: string): Boolean; Var SymlinkRec: TSymLinkRec; attr: TFileAttributes; begin Result := False; TFile.GetAttributes (Filename, false); if TFileAttribute.faSymLink in Attr then begin TFile.GetSymLinkTarget(Filename, SymlinkRec); if SymlinkRec.TargetName <> '' then begin Result := True; R7... Determine the control under the mouse position If you want to find out which control is located at the current mouse position, you can do this with the function "ObjectAtPoint". Here is an example of how to get the class name of the object, over which the mouse pointer is: procedure TForm9.Timer1Timer(Sender: TObject); var obj: IControl; begin obj := ObjectAtPoint (Screen.MousePos); if obj <> NIL then begin Label2.Text := TControl (obj).classname;

220 R8... Find out on which MAC OS X operating system the program is running The record "TOSVersion" is available in the unit "System.SysUtils", which allows you to query the operating system both under Windows and MAC OS X. With "TOSVersion.ToString", you get several relevant parameters summarized together. Under Windows 7, the example looks as follows: Under MAC OS X, then: Under Linux so: If you look at the structure of the record once, you will see what features and data are available at all: TOSVersion = record public type TArchitecture = (arintelx86, arintelx64); TPlatform = (pfwindows, pfmacos); private class var FArchitecture: TArchitecture;

221 class var FBuild: Integer; class var FMajor: Integer; class var FMinor: Integer; class var FName: string; class var FPlatform: TPlatform; class var FServicePackMajor: Integer; class var FServicePackMinor: Integer; class constructor Create; public class function Check(AMajor: Integer): Boolean; overload; static; inline; class function Check(AMajor, AMinor: Integer): Boolean; overload; static; inline; class function Check(AMajor, AMinor, AServicePackMajor: Integer): Boolean; overload; static; inline; class function ToString: string; static; class property Architecture: TArchitecture read FArchitecture; class property Build: Integer read FBuild; class property Major: Integer read FMajor; class property Minor: Integer read FMinor; class property Name: string read FName; class property Platform: TPlatform read FPlatform; class property ServicePackMajor: Integer read FServicePackMajor; class property ServicePackMinor: Integer read FServicePackMinor; R9 Get the current user name in Mac OS X / Linux / Windows Under MAC OS and Linux simply take the second entry from the directory "GetHomepath" command, under Windows the third: function GetComputerUserName: string; begin {$IF DEFINED (MACOS) or DEFINED (Linux)} result := ExtractFileName (GetHomePath); {$ENDIF} {$IFDEF MSWindows} result := ExtractFileName (ExtractFileDir (ExtractFileDir (GetHomepath))) {$ENDIF} R10 Send files as an attachment of an with the system mail program A frequently used function is sending files that was created by your own

222 program. The simplest solution is to transfer the files to the mail-program used by the operating system. Under Windows, you can use the Microsoft MAPI. I assume that you probably already know how to do that in Windows, using the MAPI interface. If not, you can download my unit "usendmail.pas" from my devpage website, which contains the "Send Files" function used here: The cross-platform solution for Windows and MAC is the following (using an example of a form with a listbox, in which you have selected one or more files, and then click on the button "send mail"): Uses {$IFDEF MACOS} POSIX.Stdlib, {$ENDIF} {$IFDEF MACOS} usendmail.pas, {$ENDIF} procedure Tf_Main.SendMailClick(Sender: TObject); var L: Integer; app, s: String; sl: TSTringList; begin sl := TStringList.create; {$IFDEF MSWINDOWS} for L := 0 to lbbilder.count - 1 do begin if lbbilder.listitems[l].isselected then begin sl.add (lbbilder.items[l]); // this here with the MAPI files SendFiles (sl); {$ENDIF} {$IFDEF MACOS}

223 for L := 0 to lbbilder.count - 1 do begin if lbbilder.listitems[l].isselected then begin sl.add (' "' + lbbilder.items[l] + '"'); s := StringReplace (Trim (sl.text), #10, '', [rfreplaceall]); app := '/Applications/Mail.app'; _system(pansichar ('open -a' + AnsiString (app + ' ' + s))); {$ENDIF} sl.free; In the MAC OS X solution, a string is made of the files to be sent. It holds the file names in quotes and separates them by a space. The Apple Mail program is used as a mail program here. The parameters 'open -a' simply mean that the function "_system" should start an application, to which, separated by a space, you pass over the files to be sent. On Linux, it is enough to pass the data as parameter, first the program-name and than the filenames, separated by a space. Note: If you want to give the user the option to use another mail program, you could offer the appropriate options in a own setting dialog. He could, then, simply select the mail program which he used from the Applications folder. Instead of app := '/Applications/Mail.app'; you would use app := '/Applications/UserMailprog.app'; where upon "UserMailprog" is the mail program selected by the user. One requirement is, of course, that this program must also support the reading

224 of the passed parameters for the file names. R11 Provide the user with help-files under Win & MAC & Linux Under Windows, you can use the Microsoft HTML Help Workshop to create a ".chm" help-file or another professional program which generates these files. The Help Workshop use as source HTML files. Other professional programs work either with HTML files or can issue, at least, the help text in such a format. And this is the solution: use HTML files under both Windows and MAC OSX. That will allow you to call and view the help from your program. The files are then displayed in the browser. In Delphi, you can include the required HTML files in your application bundle by using the deployment feature and transfer the files to the MAC OS folder. Here you can see an example of the "index-en.htm", which contains the help text for the English language version and the "index.htm" for the German language version. For more extensive programs you can also create multiple HTML help texts and include them in your program. In your program, call the HTML files with the "pf_showhelp" function ("AktLang" is here a global variable, managed by the program. It keeps the information about the language used currently): procedure Tf_Main.mnu_ContentClick(Sender: TObject); var

225 fn: string; begin if AktLang = 'DE' then begin fn := IncludeTrailingPathDelimiter (AppPath) + 'index.htm'; if AktLang = 'EN' then begin fn := IncludeTrailingPathDelimiter (AppPath) + 'index-en.htm'; pf_showhelp (fn); Whereby the procedure "pf_showhelp" is defined as follows: Uses {$IFDEF MSWindows} uses Windows, ShellApi, Classes; {$ENDIF} {$IFDEF MACOS} Uses System.Classes, POSIX.Stdlib; {$ENDIF}... procedure pf_showhelp (HTMLFile: string); begin {$IFDEF MSWINDOWS} ShellExecute (0,'open',Pchar (HTMLFile),nil,nil,0); {$ELSE} _system(pansichar ('open ' + AnsiString (HTMLFile))); {$ENDIF} By the way, I recommend that you do not directly call a windows function from a unit, where your program logic is. It is better to place this in extra-units, e.g., a "WinOnly.pas" and a "Shared.plattform.pas". In "WinOnly.pas", you ship

226 features that only exist under Windows, and in "Shared.plattform.pas", the functions that are available for several platforms. This approach also has the advantage that you do not have to work all the time with IFDEF's in your program. Then it is also much easier to expand your program for another platform (e.g. Linux) later. R12... Drag and drop text from external source (e.g. browser) to a TEdit box At the request of a customer, I have integrated a extension in my accounting program with a functionality that one can drag a text selected from the browser onto an edit-field of the program. And the text will be placed there, when the user release the mouse-button. For this, you only need to complete the relevant events as follows: procedure Tf_Bill.Edit1DragOver(Sender: TObject; const Data: TDragObject; const Point: TPointF; var Operation: TDragOperation); begin Operation := TDragOperation.Copy; procedure Tf_Bill.Edit1DragDrop(Sender: TObject; const Data: TDragObject; const Point: TPointF); begin if (Data.Data.TypeInfo <> NIL) and (Data.Data.TypeData <> NIL) then begin TEdit (Sender).Text := Data.Data.ToString; Except for the Internet Explorer of Windows, this functionality is supported by most browsers and indeed also by cross platforms (e.g., even Safari on the MAC). The drag and drop of text works even with many word-processing programs. R13... Store additional information in standard objects From the VCL, you might know the property "Tag" which has almost every object and represents an integer value. In FireMonkey, you can set such a Tag value also, for example, with the

227 Objectinspector. Except for that, however, there are also existing the properties "TagString", "TagFloat" and "TagObject" for an object or a control (TFMXObject). This is extremely useful if you want to store additional data, information or objects to a specific control. These values, however, can be read or written only at runtime (not via the Objectinspector). Overall, it's a very useful extension under FMX. R14 Using ActiveControl If you have placed various controls in a form and make a query on the variable "ActiveControl", this is - unlike under the VCL - always NIL. Whether this is intentional or a bug is not clear. Anyway, while the program is running, it will sometimes be useful to know which is the active control (i.e. the one that has the focus) right now. You can directly use the property "Focused" of the form here, which is the control, that has the focus. But if you want to set the ActiveControl variable, you can do the following in the event "OnFocusChanged" of the form: procedure TForm9.FormFocusChanged(Sender: TObject); begin ActiveControl := TControl (Focused.GetObject); //if ActiveControl <> NIL then begin // Label1.Text := 'Aktives Control: ' + // ActiveControl.ClassName + ' (' + // ActiveControl.Name + ')'; // You can activate here the disabled lines in the source-code above and see what will be shown when you change the focus to an individual control (and, for example in a grid with F2 to get into the edit mode).

228 R15 Replace OnDrawItem event of the ListBox from VCL with the OnPainting event of the TListBoxItems Indeed, the ListBox has no "OnDrawItem" event as the VCL listbox, but the ListBoxItem has an "OnPaint" or "OnPainting" event. Here you can, just like in the old VCL-way, do drawings as you want. That is, for example, useful if you have data stored in internal objects that have been connected to the ListBoxItems (or otherwise holded somewhere in a list or database). For the demo below, I have kept it simply and demonstrate it without associated data objects. The ListBoxItems do not contain any text (and they should not because it will be drawn by FireMonkey by default). I get text from the name of the ListBoxItems then. So only the drawing process is demonstrated here: procedure TForm22.ListBoxItem1Painting(Sender: TObject; Canvas: TCanvas; const ARect: TRectF); var Flags: TFillTextFlags; begin With TListBoxItem(sender) do begin canvas.beginscene; canvas.fill.kind := TBrushKind.bkSolid; Flags := [TFillTextFlag.ftRightToLeft]; if Name = 'ListBoxItem3' then begin

229 if ListBox1.ListItems[ListBox1.ItemIndex] <> TListBoxItem(sender) then begin Canvas.Clearrect (Arect, TAlphaColorRec.Yellow); if Name = 'ListBoxItem2' then Canvas.Fill.Color := TAlphaColorRec.red else Canvas.Fill.Color := TAlphaColorRec.black; Canvas.FillText(ARect, name, true, 1, flags, TTextAlign.taTrailing, TTextAlign.taCenter); canvas.endscene; Note again: The property "Text" of the TListboxItems has no content itself, of course, because this would result in duplicate drawings (text overlays). You can use the "Tagstring" instead of the "Text" property of a ListboxItem if you want to keep the data in a Listbox-Item. Here is the result: R16 Load Bitmap from resource file (for retina display) From Delphi XE5 on, you can easily add to your program resources that can later be loaded into a component. To distinguish: here, we talk about a program resource but not about the MultiResBitmap, into which you can load multiple

230 bitmaps at design time (also with different resolutions - in so far, this tip here is an alternative solution). When you run the program on MAC OS X, it may be that the user uses a screen with double resolution, the so-called. Retina display. If it is important for your program that certain bitmaps can also be displayed with the double resolution, you can create a bitmap with a normal resolution and save additionally one with the double resolution in the program resource. At runtime, examine the present resolution, and then load the appropriate bitmap in your image component. First, how do you get the bitmaps in the program resource? Here, you can use the command "Resources and Images" under the "Projects" menu. Add a normal sized image and provide the file name with a "1" at the end. Images with the double resolution will be provided with a "2" at the end. Rename also the identifier as "Dia1". Warning: Upper and lower case counts! So if you enter here "Dia1" and use in the source code "dia1", the resource will not be found. It is also important that you change the resource type of "BITMAP" to "RCDATA", otherwise it will not work. At runtime, for example, in the OnCreate event, you can do it like this: // Unit FMX.Platform is required procedure TForm1.FormCreate(Sender: TObject); var

231 RS : TResourceStream; ScreenSrv: IFMXScreenService; scale: single; begin if TPlatformServices.Current.SupportsPlatformService (IFMXScreenService, IInterface(ScreenSrv)) then Scale := ScreenSrv.GetScreenScale else Scale := 1.0; if Scale < 2.0 then begin RS := TResourceStream.Create(HInstance,'dia1', RT_RCDATA); Image1.MultiResBitmap.LoadItemFromStream(RS,1.0); end else begin RS := TResourceStream.Create(HInstance,'dia2', RT_RCDATA); Image1.MultiResBitmap.LoadItemFromStream(RS,2.0); FreeAndNil(RS); So check first with the ScreenService which screen resolution is present. "1.0" would be normal and everything else has a higher resolution. Then, you create a resource stream, load the bitmap into it and then load the bitmap from the stream into the image component. The detour via the resource stream is, unfortunately, necessary because the image component cannot load directly the image from a program resource. R17 Swap items in a listbox From the VCL, you know the function ListBox1.Items.Exchange(); To swap two items, for example, you could use the following source code (assumed that there would be 10 entries in the listbox): procedure TForm38.Button1Click(Sender: TObject); begin Listbox1.Items.BeginUpdate;

232 Listbox1.Items.Exchange(2,1); Listbox1.Items.EndUpdate; Under FireMonkey, you have to do this: procedure TForm4.btExchangeClick(Sender: TObject); begin lb.itemsexchange(lb.listitems[2], lb.listitems[1]); Unlike under the VCL, you must omit here the BeginUpdate and EndUpdate. Explanation of this: Internally, the function "Items.Exchange" uses a "Listbox.BeginUpdate" and a "Listbox.EndUpdate" by itself. If you use, by yourself, "BeginUpdate" before, the internal routine assumes that the list box is being updated and does not perform the change. Unfortunately, this is not documented anywhere, but once you know it, OK. R18 Swap items in a Listbox via Drag & Drop The listbox property "Allowdrag" must set to "True". In the "OnDragDrop" event you must respond to the drop: procedure TForm1.ListBox1DragDrop(Sender: TObject; const Data: TDragObject; const Point: TPointF); var LI: TListBoxItem; begin if Data.Source is TListboxItem then begin LI := ListBox1.ItemByPoint (Point.X, Point.Y); Listbox1.ItemsExchange(LI, TListboxItem (Data.Source)); R19 Using FMX functions in a VCL application via DLL Converting an existing VCL application to a FireMonkey application can be done in a radical approach, which means to convert everything in one action.

233 The disadvantage is that this can take a long time on a larger VCL project and in the meantime you cannot change much in the current application any more. The alternative could be a softer transition. For example, you can outsource step by step dialogs and related functions into a FireMonkey DLL. Here, you can also use the extended capabilities (graphics, GPS-functions, etc.) so that the current application can directly benefit from it. Perhaps you may not want to convert the project in general to FireMonkey, but for certain functionalities, you would like to use FireMonkey. In both variants, it makes sense to provide this function by using a FireMonkey DLL. This is not that difficult and it works much like under the VCL. Here, I show you an example of how I have added a new filter effect to the VCL-image editing program "PixPower Photo & Draw" with a FireMonkey DLL. Although the DLL has generated a size of about 4 MB, it affects my installation package only with a value of 1.3 MB. In the VCL application, I have a bitmap that I save as a bitmap stream and pass it to the FMX-DLL. Unfortunately, I cannot directly pass the bitmap as "TBitmap" to the DLL, because VCL and FireMonkey bitmaps are incompatible with each other. In the DLL, the bitmap is displayed in a dialog in the" TImageViewer" component, to which I've added a "PaperSketch" effect. The intensity is adjusted via a track bar. If the user confirm the result with "OK", the effect will be then applied to the bitmap and this is written back into the stream. Here a little trick is used because FireMonkey writes a bitmap as a PNG stream by default. Therefore, a separate class "TMyBitmap" derived from TBitmap is used. It overwrites the save stream procedure and adjusts it in a way, that the stream can be saved as bitmap stream. That's the way how to do it: With the menu "File", command "New", create a new Dynamic-link library:

234 library FMXFilters; uses FMX.Forms, System.SysUtils, System.Classes, FrmFilter in 'FrmFilter.pas' {F_Filters}; {R *.res} exports ShowBitmapFromStream; begin end. If you have created the library, the elements marked here in bold are not available automatically. You have to add manually the Unit FMX.Forms so that it is clear that it should be a FireMonkey DLL. Depending on whether you are creating the library in an already open VCL project or separately, it may be that Delphi indicates that the DLL here is taken as a FireMonkey project. You can positively confirm this query. The Unit FrmFilter is a form unit that I have created under "File", "New", "FireMonkey Form": Note: This command is only displayed when you have activated the DLL project in the Project Explorer:

235 The form looks like this: In the structure view, it looks like this: In the source code I have defined the following function before the "Implementation" section: Function ShowBitmapFromStream (ms: TMemoryStream): Boolean; export; This is the function provided as externally callable function available through the "exports" statement in the library file.

236 Note 1: If you want to pass a string instead of a bitmap to the DLL, you should use either a ShortString, PChar or WideString. So you don't need to take the ShareMem unit into the unit uses and you don't need to deliver the BORLNDMM.DLL with your application. Note 2: If you want to ensure that the generated DLL can be called not only from Delphi programs but also from the programs created by other development environments, you should use an "IStream" rather than a memory stream. Here is the implementation of this function in the form file (the units FMX.Filter, FMX.Effects, FMX.Filter.Effects and FMX.Surfaces are required under uses): function ShowBitmapFromStream (ms: TMemoryStream): Boolean; var Filter: FMX.Filter.TFilter; begin Filter := TFilterManager.FilterByName('PaperSketch'); try F_Filters := TF_Filters.Create(Application); F_Filters.ImageViewer1.bitmap.LoadFromStream(ms); if F_Filters.ShowModal = mrok then begin Filter.ValuesAsBitmap['Input'] := F_Filters.ImageViewer1.bitmap; Filter.ValuesAsFloat ['BrushSize'] := F_Filters.TrackBar1.Value; F_Filters.ImageViewer1.bitmap := TBitmap (Filter.ValuesAsBitmap['Output']); TMyBitmap (F_Filters.ImageViewer1.bitmap). SaveToStream (ms); Result := True; end else begin Result := False; finally F_Filters.Free;

237 Here are the adjustments, required to store the bitmap stream: Type TMyBitmap = class (TBitmap) procedure SaveToStream(Stream: TStream); Implementation procedure TMyBitmap.SaveToStream(Stream: TStream); var Surf: TBitmapSurface; begin Surf := TBitmapSurface.Create; try Surf.Assign(Self); TBitmapCodecManager.SaveToStream(Stream, Surf, '.bmp'); finally Surf.Free; With the Filter-Manager and the name of the filter function the wanted effect "PaperSketch" is selected. Then, the FMX dialog is created. The bitmap stream is loaded into the bitmap of the TImageViewer. If the user has set the desired intensity of the effect with the trackbar and then confirms this with "OK", the setting of the trackbar-value will be applied. Then,the modified bitmap with the derived class is stored as "BMP' bitmap stream (i.e., a bitmap in RGB format). In the VCL application the following unit is now added: unit ufmxlink; interface uses Windows, Dialogs, Classes; type TShowBitmapFromStream = function(ms: TMemoryStream): Boolean; var ShowBitmapFromStream : TShowBitmapFromStream = nil; DllHandle : THandle;

238 implementation initialization if DllHandle = 0 then begin DllHandle := LoadLibrary('FMXFilters.dll'); if DllHandle > 0 then := GetProcAddress(DllHandle, 'ShowBitmapFromStream'); end else begin MessageDlg('The function ShowBitmapFromStream / ' + ' the DLL-file "FMFilters.dll" ist not available', mtinformation, [mbok], 0); finalization if DLLHandle <> 0 then FreeLibrary(DLLHandle); end. Under "Type", a function is defined, which corresponds to the export function of the DLL. Under "Var", "ShowBitMapFromStream" is introduced as procedure variable. In the initialization section, the DLL is loaded and, as a result, our previously declared procedure will be assigned to the memory-address of the function in the DLL. If you include this VCL-unit in your VCL application, you can call the function "ShowBitmapFromStream" from here. So, for example: Var MemStream: TMemorySteam; TempFileName: String; Begin TempFileName := // impose temporary file name ABitmap.saveToStream (MemStream); // Save the bitmap as a // MemoryStream MemStream.position := 0; If ShowBitmapFromStream (MemStream) then begin MemStream.Position := 0;

239 ABitmap.LoadFromStream (ms) // load Bitmap back End; NOTE: To get it to work, you have to include the unit "Winapi.GDIPOBJ" in the main form of your VCL application, in fact directly in the USES section of the interface-section (not in the uses-clause in the implementation section, which would be not enough). This unit is required so that the GDI function can be initialized also for the VCL application. This can only be done through the main form. If you are interested, you can take a look at the functionality in the program once here ( or simply in a YouTube video in my PixPower channel, where I have demonstrated this filter: Note: I've seen it in some situations that the call to "FreeLibrary" in the Finalization section causes the program to hang. If you are experiencing problems, just remove the call, Windows automatically removes the DLL from memory when the program has finished. R20 Draw text in TGrid right, or centered From XE6 on, the TGrid contains, under "TextSettings", the possibility to choose the horizontal alignment. With "HorzAlign", you can set the text to be left-justified, centered or right-justified. However, this setting applies to all columns that are displaying text. The TColumns or TStringColumns you have placed into the TGrid have no property like the TGrid. But this could be necessary, if the text in one column should be displayed justified on the left, and in another column to the right (e.g. monetary amounts). Here, it is useful to set at first the Tag-value of the TStringColumns that should be aligned to the right with the value of "1". For all columns that have the value "1", we give in the Grid.GetValue an empty value back so that the grid itself does not carry out a drawing action here: procedure TForm9.Grid1GetValue(Sender: TObject; const Col, Row: Integer; var Value: TValue);

240 begin if TGrid (sender).columnbyindex (col).tag = 1 then begin exit;... In the event of the OnDrawColumnCell of the TGrid, we call the DrawCellRight function for all columns: procedure TForm9.Grid1DrawColumnCell(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates); begin DrawCellRight (Sender, Column, canvas, bounds, Row, Value); And now to the user-defined function. Here, we also use the OnGetValue event of the TGrid to get the value of the cell. Temporarily we set the Tag value of the TColumn to "0" so that the value is returned to us (Remember: We have installed a supplement above so that the value is only returned if the Tag value of the column has the value "0". It will look like this: procedure DrawCellRight (Sender: TObject; Column: TColumn; canvas: TCanvas; bounds: TRectF; Row: Integer; Value:TValue); var B: TRectF; V: TValue; begin if Column.Tag = 1 then begin Column.Tag := 0; V := Value; TGrid (Sender).OnGetValue(Sender, column.index, Row, V); B := Bounds; B.Right := B.Right-1; DrawTextEx(canvas, B, TAlphaColorRec.black, V.tostring, TTextAlign.Trailing); Column.Tag := 1; And here is the helper-function, which draws the text for us: procedure DrawTextEx (Z: TCanvas; arec: TRectF; ATextColor: TAlphaColor; S: String; a: TTextalign);

241 var r: TRectF; tf: tfilltextflags; h: TTextalign; begin h := TTextAlign.taCenter; Z.Fill.Color := ATextColor; Z.BeginScene; Z.FillText(arec,S,false,1,tf,a,h); Z.EndScene; The result is that, for all columns whose tag-value are "0", the drawing starts at the left margin (done by the TGrid itself), and for all those with tag-value "1", the text is right justified (done by our drawing function): R21 Draw text in TStringGrid right or centered Even in TStringGrid, you can set only the same text-alignment for all columns. We have also to draw the text by ourself in the "OnDrawColumnCell"-event. This solution assumes that the string grid does not hold the data but only displays the relevant content (as it should be). Let the left-aligned text output as default and set the Tag value of the column that you want to be right-justified to "1" and that to be output centered to "2". Then it looks so in the draw-event: procedure TForm9.StringGrid1DrawColumnCell(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF; const Row: Integer; const Value: TValue; const State: TGridDrawStates); var Flags: TFillTextFlags; ar: TRectF; S: string; begin Flags := [TFillTextFlag.ftRightToLeft]; canvas.beginscene; ar := bounds; ar.inflate(-1,-1);

242 canvas.clearrect(ar); canvas.fill.color := TAlphaColorrec.Black; S := Row.ToString; case column.tag of 0: canvas.filltext(bounds, S, True, 1, flags, TTextAlign.taTrailing,TTextAlign.Center); 1: canvas.filltext(bounds, S, True, 1, flags, TTextAlign.taLeading,TTextAlign.Center); 2: canvas.filltext(bounds, S, True, 1, flags, TTextAlign.taCenter,TTextAlign.Center); canvas.endscene; Here is the result: R22 Working with the "visible" property of controls From XE7 on, there is no longer the property "DesignVisible", that was available beside the property "Visible". When now you set at design time a control to "Visible = False", it is also no longer visible at design time. That makes it a little difficult to choose the control, e.g., for settings to make in the Objectinspector. Use in this case the tree view where you can easily select and activate the invisible control. If you upgrade a project from a previous version of Delphi, and a control no longer appears to be available, check if you can find it in the structure view and if the "Visible" property just stood to "False". R23 Prevent unintended shortening of TLabel text From XE6 on, under "TextSettings the default setting for "Trimming" is

243 "character" to display the label text. AutoSize is turned off. This can sometimes lead to the situation that the text is shortened at runtime with "..." when the display width is not wide enough. You should either set "AutoSize" to True or turn off "AutoSize" and the trimming and leave more space for the display of the text in advance. This is also to be considered because, for example, under Windows the display width is sufficient but not under MAC OS, because the fonts sometimes are slightly different. It is therefore advisable under all platforms to look at the dialogs at runtime. Currently I suggest rather to turn off AutoSize, because I have found that relatively many times the text is not displayed correctly in the hight (e.g. "g" and "p" has missing parts above and below), in particular on MAC OS X. You should then also slightly enlarge the height of the Label component. R24... How to show a pop-up menu at a special position Maybe you are faced with the situation that the user can click on a specific item and then a pop-up menu should be displayed above or below it. Here is an example that the user clicks on a panel and then a pop-up menu will be displayed below it: You can do it like this: procedure Tfrm_Main.pnMahnungRangeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin hs_showpopup (self, pnmahnungrange, popmahnung, unten); The function "hs_showpopup" is defined as follows: procedure hs_showpopup (frm: TForm; bn: TControl; pop: TPopupMenu; ObenUnten: Integer); var FP: TPointF; begin

244 FP.X := 0; FP.Y := 0; //Transposes the coordinates in the context of the form. FP := bn.localtoabsolute(fp); //Transposes the coordinates in the context of the screen. FP := frm.clienttoscreen(fp); //Display the popup menu at the calculated coordinates. pop.popup(fp.x, FP.Y + bn.height); This feature also works on multi-monitor systems. R25 Determine the document directory For all platforms you can use the record "TPath" from the unit "System.IOUtils". It contains a lot of information about directories that can be accessed with the corresponding functions: procedure TForm2.FormCreate(Sender: TObject); var DocPath: String; begin DocPath := TPath.GetDocumentsPath; Here is the result for DocPath on my MAC or Windows computer: under MAC OS X: /Users/harrystahl/Documents under Windows: C:\Users\Harry-Dev\Documents under Linux: "/home/harry/dokumente" Tip: Click once on "TPath", holding down the Ctrl key and Delphi will show you the TPath record. Explore the individual variables and functions that are available there (in the public sector). It is really worthy, some of them you can use again later, for sure. For example, you can also use the images directory (TPath.GetPicturesPath) or the video directory (TPath.GetMoviesPath). R26 Improve the font quality (especially on Windows) Under Windows, the display quality of the fonts under FireMonkey is not optimal. I improve it by turning off the Direct2D functionality in the project file before the initialization: begin FMX.Types.GlobalUseDirect2D := False;

245 Application.Initialize; Application.CreateForm(TF_Main, F_Main); Application.Run; end. Hint: The unit FMX.Types must be included. R27 Select a folder with a dialog With "SelectDirectory", you can now select a folder: procedure TForm2.Button1Click(Sender: TObject); var dir, root: string; begin root := ''; // root := System.IOUtils.TPath.GetPicturesPath; if SelectDirectory ('Bitte wählen Sie ein Verzeichnis', root, dir) then begin ShowMessage ('You have selectd: ' + dir); The Unit FMX.Dialogs must be integrated (for "ShowMessage"). The first parameter is used to specify a description that is displayed in the title bar of the dialog. In the second parameter, you can specify a directory, from which the dialog starts (by default, it is the document directory). The third is a VAR parameter and returns the selected directory name. R28... Let a column in a string grid occupy the remaining space You have a string grid with multiple columns and when changing the size of the grid, you want always that a particular column responds to the changes in size and occupy the free space in the grid. It should be noted that the calculation can work properly only when the grid has been shown once, which means the OnShow-event of the form has been once run through completely. For this purpose, you must use a timer set enabled in the OnShow event with the interval of 25 ms. At the first time the timer event is triggered, you disable the timer and make the calculation as wanted (later you do the calculations on the OnResize event of the form or the grid).

246 It could look altogether as the follwoing: var Form9: TForm9; VarCol: Integer; implementation {$R *.fmx} procedure TForm9.FormCreate(Sender: TObject); begin VarCol := 0; // für die Erste // VarCol := StringGrid1.ColumnCount-1; // z.b. für die letzte Spalte function AColWidth(Grid: TStringGrid; VarCol:Integer): Extended; var i: integer; awidth: Extended; add: Single; begin awidth := 0; for i := 0 to Grid.ColumnCount - 1 do if i <> VarCol then awidth := awidth + Grid.Columns[i].Width + 1; if (Grid.VScrollBar <> NIL) and (Grid.VScrollBar.Visible) then add := Grid.VScrollBar.Width else add := 0; Result := Grid.ClientWidth - awidth -add- Grid.columnCount;; procedure TForm9.FormResize(Sender: TObject); begin TStringColumn (StringGrid1.ColumnByIndex (VarCol)).width:= AColWidth(StringGrid1, VarCol); R29... Create missing components with Frames You may need a replacement for a component that is either not already available for FMX or a particular platform. Suppose you need a simple chart component, then create a simple solution with a frame.

247 Below is a screenshot of a frame that provides a simple BarChart solution, here at runtime: The only task in the later use of this frame is to fill the StringGrid with a few meaningful data and then call the method "UpdateChart" of the frame. The StringGrid can be displayed or hidden with the "Show data list" checkbox at runtime, or directly at the first display. And this is how the code looks like: procedure TForm71.bnMakeChartClick(Sender: TObject); var L: Integer; begin With FrBarchart1 do begin ChartHeader.Text := 'Jahresumsätze von 2007 bis 2016'; sctxt.header := 'Jahr'; scval.header := 'Umsatz'; sgdata.rowcount := 10; for L := 0 to sgdata.rowcount-1 do begin sgdata.cells[0,l] := ( L).ToString; sgdata.cells[1,l] := ( Random (12000)).tostring; UpdateChart;

248 Here you can set a header for the graphic with "ChartHeader.text". With "sctxt" and "scval" you access the headers of the TStringColumns and set a meaningful heading for the data. Then we simply created the year dates and a few random sales figures for a 10-season period. So also the use of the FrameBarChart is kept fairly simple. Developing the FrameBarChart did not take much time, so the frame looks at design time: When we look at the structure list, we see that the chart frame consists of TLayouts, rectangles, TText components, and a TPlotGrid. So everything is just standard components of FireMonkey, with which you can easily generate something new. Finally we created here with the TLayout "LayBar" a kind of template, which is

249 simply duplicated and then the corresponding values are set. Your copies are placed in the initially empty TLayout "LayChartInner". Then you can delete the copies with "LayChartInner.DeleteChildren" when you re-use or update the chart. The functional source code of the unit does not have more than 80 lines of text. In addition to the generation of the chart, the system responds to resizing events and gives a function to copy the generated chart graphic to the clipboard. And so the function "UpdateChart" looks: procedure TFrBarChart.UpdateChart; var barcount, L: Integer; lay: TLayOut; barwidth, barspace, barheightmax, barval, barvalmax: Single; T: TText; bartxt: string; begin LayChartInner.DeleteChildren; PlotGrid1.Frequency := rtinner.height / 12; barspace := 20; barcount := sgdata.rowcount; barwidth := ( LayChartInner.Width - (barspace * barcount) ) / (barcount+1); barheightmax := LayChartInner.Height-30; for L := 1 to barcount do begin barvalmax := max (barvalmax,sgdata.cells[1,l- 1].ToSingle); for L := 1 to barcount do begin Lay := TLayOut (rtinner.findstyleresource ('layoutbarprototype', true)); Lay.Width := barwidth; bartxt := sgdata.cells[0,l-1]; barval := sgdata.cells[1,l-1].tosingle; if lay<> NIL then begin lay.parent := LayChartInner;

250 lay.position.x := ((L * BarSpace) + (L * barwidth)) - barwidth; // - barwidth / 2); lay.height := (barheightmax / (barvalmax / barval)); lay.visible := True; lay.position.y := LayChartInner.Height - lay.height; T := TText (lay.findstyleresource ('bartext', false)); if T <> NIL then begin T.Width := Barwidth + BarSpace; T.Text := bartxt; T.Position.Y := Lay.height; T.Position.X := - (BarSpace / 2); T := TText (lay.findstyleresource ('barval', false)); if T <> NIL then begin T.Text := barval.tostring; T.Width := Barwidth + BarSpace; T.Position.X := - (BarSpace / 2); LayBar.Visible := false; As a reminder, it is only a small demo, so you can still optimize and expand it. Add a Y-axis with appropriate values, possibly display an optional legend, etc. Or display the values of the numbers in the right-aligned grid (see tip R20). Here you can download the demo including frame and use it for your own purposes: R30... Moving controls at runtime in the form Possibly you want to offer in your program a functionality with which the user can move the elements (Editfield, Memo, Listbox, whatever) in the form to create their own data masks.

251 The TSelection component is well suited for this task. Generally it is designed to be moved on the surface of the form and to be resized by using selection points. In this respect, you simply have to temporarily put the element that is to be moved into the TSelection, turn off the hit property of the element to be moved, and move the element (in truth the TSelection) with the next click. If that is done, you set back the former parent of the moved component and that was it already. Here is a screenshot of the demo program at design time and the source code: Here is the source code: procedure TForm10.FormCreate(Sender: TObject); begin Selection1.Visible := false; Switch1.IsChecked := false; procedure TForm10.Rectangle2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); begin if Switch1.IsChecked = false then exit; selection1.visible := True; if selection1.childrencount > 0 then begin with TControl (selection1.children[0]) do begin Align := TAlignLayout.None; SetBounds (Selection1.position.X,

Table of Contents Foreword Introduction About the book About the author Contact information Chapter 1: What is FireMonkey?

Table of Contents Foreword Introduction About the book About the author Contact information Chapter 1: What is FireMonkey? Table of Contents Foreword... Page 10 Introduction... Page 11 About the book... Page 11 About the author... Page 11 Contact information... Page 11 Chapter 1: What is FireMonkey?... Page 12 Chapter 2: How

More information

Delphi XE2. evelopment. Delphi XE2 ios Development 2 nd edition, 1 st May 2012

Delphi XE2. evelopment. Delphi XE2 ios Development 2 nd edition, 1 st May 2012 Delphi XE2 evelopment Delphi XE2 ios Development 2 nd edition, 1 st May 2012 Author: Bob Swart (aka Dr.Bob) Bob Swart Training & Consultancy (ebob42) Table of Contents 1. Configuring Delphi XE2 for ios

More information

Basic Concepts. Launching MultiAd Creator. To Create an Alias. file://c:\documents and Settings\Gary Horrie\Local Settings\Temp\~hh81F9.

Basic Concepts. Launching MultiAd Creator. To Create an Alias. file://c:\documents and Settings\Gary Horrie\Local Settings\Temp\~hh81F9. Page 1 of 71 This section describes several common tasks that you'll need to know in order to use Creator successfully. Examples include launching Creator and opening, saving and closing Creator documents.

More information

The scripting system handles two types of components: Visual and Non-visual components.

The scripting system handles two types of components: Visual and Non-visual components. Forms and Components Old Content - visit altium.com/documentation Modified by on 13-Sep-2017 Parent page: DelphiScript Overview of Graphical Components The scripting system handles two types of components:

More information

Goldfish 4. Quick Start Tutorial

Goldfish 4. Quick Start Tutorial Goldfish 4 Quick Start Tutorial A Big Thank You to Tobias Schilpp 2018 Fishbeam Software Text, Graphics: Yves Pellot Proofread, Photos: Tobias Schilpp Publish Code: #180926 www.fishbeam.com Get to know

More information

CHAPTER 1 COPYRIGHTED MATERIAL. Getting to Know AutoCAD. Opening a new drawing. Getting familiar with the AutoCAD and AutoCAD LT Graphics windows

CHAPTER 1 COPYRIGHTED MATERIAL. Getting to Know AutoCAD. Opening a new drawing. Getting familiar with the AutoCAD and AutoCAD LT Graphics windows CHAPTER 1 Getting to Know AutoCAD Opening a new drawing Getting familiar with the AutoCAD and AutoCAD LT Graphics windows Modifying the display Displaying and arranging toolbars COPYRIGHTED MATERIAL 2

More information

HYPERSTUDIO TOOLS. THE GRAPHIC TOOL Use this tool to select graphics to edit. SPRAY PAINT CAN Scatter lots of tiny dots with this tool.

HYPERSTUDIO TOOLS. THE GRAPHIC TOOL Use this tool to select graphics to edit. SPRAY PAINT CAN Scatter lots of tiny dots with this tool. THE BROWSE TOOL Us it to go through the stack and click on buttons THE BUTTON TOOL Use this tool to select buttons to edit.. RECTANGLE TOOL This tool lets you capture a rectangular area to copy, cut, move,

More information

Designer Reference 1

Designer Reference 1 Designer Reference 1 Table of Contents USE OF THE DESIGNER...4 KEYBOARD SHORTCUTS...5 Shortcuts...5 Keyboard Hints...5 MENUS...7 File Menu...7 Edit Menu...8 Favorites Menu...9 Document Menu...10 Item Menu...12

More information

Chapter 2 Using Slide Masters, Styles, and Templates

Chapter 2 Using Slide Masters, Styles, and Templates Impress Guide Chapter 2 Using Slide Masters, Styles, and Templates OpenOffice.org Copyright This document is Copyright 2007 by its contributors as listed in the section titled Authors. You can distribute

More information

In the first class, you'll learn how to create a simple single-view app, following a 3-step process:

In the first class, you'll learn how to create a simple single-view app, following a 3-step process: Class 1 In the first class, you'll learn how to create a simple single-view app, following a 3-step process: 1. Design the app's user interface (UI) in Xcode's storyboard. 2. Open the assistant editor,

More information

Creating Reports in Access 2007 Table of Contents GUIDE TO DESIGNING REPORTS... 3 DECIDE HOW TO LAY OUT YOUR REPORT... 3 MAKE A SKETCH OF YOUR

Creating Reports in Access 2007 Table of Contents GUIDE TO DESIGNING REPORTS... 3 DECIDE HOW TO LAY OUT YOUR REPORT... 3 MAKE A SKETCH OF YOUR Creating Reports in Access 2007 Table of Contents GUIDE TO DESIGNING REPORTS... 3 DECIDE HOW TO LAY OUT YOUR REPORT... 3 MAKE A SKETCH OF YOUR REPORT... 3 DECIDE WHICH DATA TO PUT IN EACH REPORT SECTION...

More information

SPARK. User Manual Ver ITLAQ Technologies

SPARK. User Manual Ver ITLAQ Technologies SPARK Forms Builder for Office 365 User Manual Ver. 3.5.50.102 0 ITLAQ Technologies www.itlaq.com Table of Contents 1 The Form Designer Workspace... 3 1.1 Form Toolbox... 3 1.1.1 Hiding/ Unhiding/ Minimizing

More information

OpenForms360 Validation User Guide Notable Solutions Inc.

OpenForms360 Validation User Guide Notable Solutions Inc. OpenForms360 Validation User Guide 2011 Notable Solutions Inc. 1 T A B L E O F C O N T EN T S Introduction...5 What is OpenForms360 Validation?... 5 Using OpenForms360 Validation... 5 Features at a glance...

More information

A Step-by-step guide to creating a Professional PowerPoint Presentation

A Step-by-step guide to creating a Professional PowerPoint Presentation Quick introduction to Microsoft PowerPoint A Step-by-step guide to creating a Professional PowerPoint Presentation Created by Cruse Control creative services Tel +44 (0) 1923 842 295 training@crusecontrol.com

More information

Impress Guide Chapter 11 Setting Up and Customizing Impress

Impress Guide Chapter 11 Setting Up and Customizing Impress Impress Guide Chapter 11 Setting Up and Customizing Impress This PDF is designed to be read onscreen, two pages at a time. If you want to print a copy, your PDF viewer should have an option for printing

More information

FirePower 4.1. Woll2Woll Software Nov 3rd, Version 4.1 Supporting RAD Studio versions: XE7. FirePower 4.

FirePower 4.1. Woll2Woll Software Nov 3rd, Version 4.1 Supporting RAD Studio versions: XE7. FirePower 4. FirePower 4.1 FirePower 4.1 Page 1 Woll2Woll Software Nov 3rd, 2014 http://www.woll2woll.com Version 4.1 Supporting RAD Studio versions: XE7 Whats new in FirePower 4.1 vs 4.0 This updates redesigns the

More information

Solo 4.6 Release Notes

Solo 4.6 Release Notes June9, 2017 (Updated to include Solo 4.6.4 changes) Solo 4.6 Release Notes This release contains a number of new features, as well as enhancements to the user interface and overall performance. Together

More information

How to...create a Video VBOX Gauge in Inkscape. So you want to create your own gauge? How about a transparent background for those text elements?

How to...create a Video VBOX Gauge in Inkscape. So you want to create your own gauge? How about a transparent background for those text elements? BASIC GAUGE CREATION The Video VBox setup software is capable of using many different image formats for gauge backgrounds, static images, or logos, including Bitmaps, JPEGs, or PNG s. When the software

More information

Impress Guide. Chapter 11 Setting Up and Customizing Impress

Impress Guide. Chapter 11 Setting Up and Customizing Impress Impress Guide Chapter 11 Setting Up and Customizing Impress Copyright This document is Copyright 2007 2013 by its contributors as listed below. You may distribute it and/or modify it under the terms of

More information

Microsoft Excel 2007

Microsoft Excel 2007 Learning computers is Show ezy Microsoft Excel 2007 301 Excel screen, toolbars, views, sheets, and uses for Excel 2005-8 Steve Slisar 2005-8 COPYRIGHT: The copyright for this publication is owned by Steve

More information

Creating Icons for Leopard Buttons

Creating Icons for Leopard Buttons Creating Icons for Leopard Buttons Introduction Among the new features that C-Max 2.0 brings to the Ocelot and Leopard controllers, one of the more sophisticated ones allows the user to create icons that

More information

1 Build Your First App. The way to get started is to quit talking and begin doing. Walt Disney

1 Build Your First App. The way to get started is to quit talking and begin doing. Walt Disney 1 Build Your First App The way to get started is to quit talking and begin doing. Walt Disney Copyright 2015 AppCoda Limited All rights reserved. Please do not distribute or share without permission. No

More information

My First iphone App. 1. Tutorial Overview

My First iphone App. 1. Tutorial Overview My First iphone App 1. Tutorial Overview In this tutorial, you re going to create a very simple application on the iphone or ipod Touch. It has a text field, a label, and a button. You can type your name

More information

OnPoint s Guide to MimioStudio 9

OnPoint s Guide to MimioStudio 9 1 OnPoint s Guide to MimioStudio 9 Getting started with MimioStudio 9 Mimio Studio 9 Notebook Overview.... 2 MimioStudio 9 Notebook...... 3 MimioStudio 9 ActivityWizard.. 4 MimioStudio 9 Tools Overview......

More information

Design and Print Instruction Manual

Design and Print Instruction Manual Diamond Design Design and Print Instruction Manual Contents Installation 1 Installing the Diamond Design Software 2-3 Installing the ORIGINAL Argox OS-214 printer drivers 4 Installing the EXCEL Argox OS-314

More information

Multimedia web page Board

Multimedia web page Board Page where the users have a space (board) to create their own compositions with graphics and texts previously inserted by the author; furthermore, the users will be able to write their own texts: Multimedia

More information

Software User's Guide

Software User's Guide Software User's Guide The contents of this guide and the specifications of this product are subject to change without notice. Brother reserves the right to make changes without notice in the specifications

More information

2 SELECTING AND ALIGNING

2 SELECTING AND ALIGNING 2 SELECTING AND ALIGNING Lesson overview In this lesson, you ll learn how to do the following: Differentiate between the various selection tools and employ different selection techniques. Recognize Smart

More information

Creating Buttons and Pop-up Menus

Creating Buttons and Pop-up Menus Using Fireworks CHAPTER 12 Creating Buttons and Pop-up Menus 12 In Macromedia Fireworks 8 you can create a variety of JavaScript buttons and CSS or JavaScript pop-up menus, even if you know nothing about

More information

Interface. 2. Interface Adobe InDesign CS2 H O T

Interface. 2. Interface Adobe InDesign CS2 H O T 2. Interface Adobe InDesign CS2 H O T 2 Interface The Welcome Screen Interface Overview The Toolbox Toolbox Fly-Out Menus InDesign Palettes Collapsing and Grouping Palettes Moving and Resizing Docked or

More information

DRAFT. Table of Contents About this manual... ix About CuteSITE Builder... ix. Getting Started... 1

DRAFT. Table of Contents About this manual... ix About CuteSITE Builder... ix. Getting Started... 1 DRAFT Table of Contents About this manual... ix About CuteSITE Builder... ix Getting Started... 1 Setting up... 1 System Requirements... 1 To install CuteSITE Builder... 1 To register CuteSITE Builder...

More information

May 10: Lesson 2 Creating your First Windows and Mac Desktop Application

May 10: Lesson 2 Creating your First Windows and Mac Desktop Application May 10: Lesson 2 Creating your First Windows and Mac Desktop Application Version: 1.1 Last Updated: May 13, 2012 Presented: May 23, 2012 Prepared by: David Intersimone David I, Embarcadero Technologies

More information

Press-Ready Cookbook Page Guidelines

Press-Ready Cookbook Page Guidelines Press-Ready Cookbook Page Guidelines table of contents These instructions are for all pages of your cookbook: Title Page, Special Pages, Table of Contents, Dividers, Recipe Pages, etc. WHAT IS PRESS-READY?

More information

4 TRANSFORMING OBJECTS

4 TRANSFORMING OBJECTS 4 TRANSFORMING OBJECTS Lesson overview In this lesson, you ll learn how to do the following: Add, edit, rename, and reorder artboards in an existing document. Navigate artboards. Select individual objects,

More information

My First Cocoa Program

My First Cocoa Program My First Cocoa Program 1. Tutorial Overview In this tutorial, you re going to create a very simple Cocoa application for the Mac. Unlike a line-command program, a Cocoa program uses a graphical window

More information

Impress Guide Chapter 1 Introducing Impress

Impress Guide Chapter 1 Introducing Impress Impress Guide Chapter 1 Introducing Impress This PDF is designed to be read onscreen, two pages at a time. If you want to print a copy, your PDF viewer should have an option for printing two pages on one

More information

UNIT Files. Procedure/Functionand Other Declarations (CONST, TYPE, VAR) can be stored under different Object Pascal Files (Library).

UNIT Files. Procedure/Functionand Other Declarations (CONST, TYPE, VAR) can be stored under different Object Pascal Files (Library). Basics of Language UNIT Files Basics of Language UNIT Files UNIT Files Procedure/Functionand Other Declarations (CONST, TYPE, VAR) can be stored under different Object Pascal Files (Library). You can reduce

More information

Section 3 Formatting

Section 3 Formatting Section 3 Formatting ECDL 5.0 Section 3 Formatting By the end of this Section you should be able to: Apply Formatting, Text Effects and Bullets Use Undo and Redo Change Alignment and Spacing Use Cut, Copy

More information

Chapter 9 Getting Started with Impress

Chapter 9 Getting Started with Impress Getting Started Guide Chapter 9 Getting Started with Impress OpenOffice.org's Presentations OpenOffice.org Copyright This document is Copyright 2005 2007 by its contributors as listed in the section titled

More information

Forms for Android Version Manual. Revision Date 12/7/2013. HanDBase is a Registered Trademark of DDH Software, Inc.

Forms for Android Version Manual. Revision Date 12/7/2013. HanDBase is a Registered Trademark of DDH Software, Inc. Forms for Android Version 4.6.300 Manual Revision Date 12/7/2013 HanDBase is a Registered Trademark of DDH Software, Inc. All information contained in this manual and all software applications mentioned

More information

Forms for Palm OS Version 4 Manual

Forms for Palm OS Version 4 Manual Forms for Palm OS Version 4 Manual Revision Date 12/05/2007 HanDBase is a Registered Trademark of DDH Software, Inc. All information contained in this manual and all software applications mentioned in

More information

Basic Concepts 1. For this workshop, select Template

Basic Concepts 1. For this workshop, select Template Basic Concepts 1 When you create a new presentation, you re prompted to choose between: Autocontent wizard Prompts you through a series of questions about the context and content of your presentation not

More information

InfoPower for FireMonkey 3.0

InfoPower for FireMonkey 3.0 InfoPower for FireMonkey 3.0 InfoPower FireMonkey 3.0 Page 1 Woll2Woll Software April 28th, 2014 http://www.woll2woll.com Version 3.0 Supported RAD Studio versions: XE5 AND XE6 (Currently only XE6) Our

More information

VisualPST 2.4. Visual object report editor for PowerSchool. Copyright Park Bench Software, LLC All Rights Reserved

VisualPST 2.4. Visual object report editor for PowerSchool. Copyright Park Bench Software, LLC All Rights Reserved VisualPST 2.4 Visual object report editor for PowerSchool Copyright 2004-2015 Park Bench Software, LLC All Rights Reserved www.parkbenchsoftware.com This software is not free - if you use it, you must

More information

SETTING UP A. chapter

SETTING UP A. chapter 1-4283-1960-3_03_Rev2.qxd 5/18/07 8:24 PM Page 1 chapter 3 SETTING UP A DOCUMENT 1. Create a new document. 2. Create master pages. 3. Apply master pages to document pages. 4. Place text and thread text.

More information

Contents. Introducing Clicker Paint 5. Getting Started 7. Using The Tools 10. Using Sticky Points 15. Free resources at LearningGrids.

Contents. Introducing Clicker Paint 5. Getting Started 7. Using The Tools 10. Using Sticky Points 15. Free resources at LearningGrids. ClickerPaintManualUS.indd 2-3 13/02/2007 13:20:28 Clicker Paint User Guide Contents Introducing Clicker Paint 5 Free resources at LearningGrids.com, 6 Installing Clicker Paint, 6 Getting Started 7 How

More information

XnView Image Viewer. a ZOOMERS guide

XnView Image Viewer. a ZOOMERS guide XnView Image Viewer a ZOOMERS guide Introduction...2 Browser Mode... 5 Image View Mode...14 Printing... 22 Image Editing...26 Configuration... 34 Note that this guide is for XnView version 1.8. The current

More information

The American University in Cairo. Academic Computing Services. Word prepared by. Soumaia Ahmed Al Ayyat

The American University in Cairo. Academic Computing Services. Word prepared by. Soumaia Ahmed Al Ayyat The American University in Cairo Academic Computing Services Word 2000 prepared by Soumaia Ahmed Al Ayyat Spring 2001 Table of Contents: Opening the Word Program Creating, Opening, and Saving Documents

More information

hdalbum User Designer Guide Collect Create Share Designer V 1.2

hdalbum User Designer Guide Collect Create Share Designer V 1.2 hdalbum User Designer Guide 2017 Collect Create Share Designer V 1.2 Table of Contents Contents Welcome to the hdalbum Designer... 2 Features... 2 System Requirements... 3 Supported File Types... 3 Installing

More information

Impress Guide. Chapter 1 Introducing Impress

Impress Guide. Chapter 1 Introducing Impress Impress Guide Chapter 1 Introducing Impress Copyright This document is Copyright 2005 2009 by its contributors as listed in the section titled Authors. You may distribute it and/or modify it under the

More information

Report Designer Report Types Table Report Multi-Column Report Label Report Parameterized Report Cross-Tab Report Drill-Down Report Chart with Static

Report Designer Report Types Table Report Multi-Column Report Label Report Parameterized Report Cross-Tab Report Drill-Down Report Chart with Static Table of Contents Report Designer Report Types Table Report Multi-Column Report Label Report Parameterized Report Cross-Tab Report Drill-Down Report Chart with Static Series Chart with Dynamic Series Master-Detail

More information

Handout Objectives: a. b. c. d. 3. a. b. c. d. e a. b. 6. a. b. c. d. Overview:

Handout Objectives: a. b. c. d. 3. a. b. c. d. e a. b. 6. a. b. c. d. Overview: Computer Basics I Handout Objectives: 1. Control program windows and menus. 2. Graphical user interface (GUI) a. Desktop b. Manage Windows c. Recycle Bin d. Creating a New Folder 3. Control Panel. a. Appearance

More information

Basic Concepts 1. Starting Powerpoint 2000 (Windows) For the Basics workshop, select Template. For this workshop, select Artsy

Basic Concepts 1. Starting Powerpoint 2000 (Windows) For the Basics workshop, select Template. For this workshop, select Artsy 1 Starting Powerpoint 2000 (Windows) When you create a new presentation, you re prompted to choose between: Autocontent wizard Prompts you through a series of questions about the context and content of

More information

VHSE - COMPUTERISED OFFICE MANAGEMENT MODULE III - Communication and Publishing Art - PageMaker

VHSE - COMPUTERISED OFFICE MANAGEMENT MODULE III - Communication and Publishing Art - PageMaker INTRODUCTION : It is one Adobe PageMaker 7.0 software is the ideal page layout program for business, education, and small- and home-office professionals who want to create high-quality publications such

More information

PowerPoint 2003: Basic Instructor s Edition

PowerPoint 2003: Basic Instructor s Edition PowerPoint 2003: Basic Instructor s Edition ILT Series COPYRIGHT Axzo Press. All rights reserved. No part of this work may be reproduced, transcribed, or used in any form or by any means graphic, electronic,

More information

ORGANIZING YOUR ARTWORK WITH LAYERS

ORGANIZING YOUR ARTWORK WITH LAYERS 9 ORGANIZING YOUR ARTWORK WITH LAYERS Lesson overview In this lesson, you ll learn how to do the following: Work with the Layers panel. Create, rearrange, and lock layers and sublayers. Move objects between

More information

ECDL Module 6 REFERENCE MANUAL

ECDL Module 6 REFERENCE MANUAL ECDL Module 6 REFERENCE MANUAL Presentation Microsoft PowerPoint XP Edition for ECDL Syllabus Four PAGE 2 - ECDL MODULE 6 (USING POWERPOINT XP) - MANUAL 6.1 GETTING STARTED... 4 6.1.1 FIRST STEPS WITH

More information

StitchGraph User Guide V1.8

StitchGraph User Guide V1.8 StitchGraph User Guide V1.8 Thanks for buying StitchGraph: the easy way to create stitch layouts for hardanger and other complex embroidery stitch types. StitchGraph is intended to allow you to create

More information

NiceForm User Guide. English Edition. Rev Euro Plus d.o.o. & Niceware International LLC All rights reserved.

NiceForm User Guide. English Edition. Rev Euro Plus d.o.o. & Niceware International LLC All rights reserved. www.nicelabel.com, info@nicelabel.com English Edition Rev-0910 2009 Euro Plus d.o.o. & Niceware International LLC All rights reserved. www.nicelabel.com Head Office Euro Plus d.o.o. Ulica Lojzeta Hrovata

More information

OX Documents Release v Feature Overview

OX Documents Release v Feature Overview OX Documents Release v7.8.4 Feature Overview 1 Objective of this Document... 3 1.1 The Purpose of this Document... 3 2 General Improvements... 4 2.1 Security First: Working with Encrypted Files (OX Guard)...

More information

Understanding File Management

Understanding File Management UNIT B Windows 2007 Understanding File Management Files You Will Need: Win B-1.bmp Win B-2.bmp Most of your work on a computer involves using programs to create files. For example, you might use WordPad

More information

My First iphone App (for Xcode version 6.4)

My First iphone App (for Xcode version 6.4) My First iphone App (for Xcode version 6.4) 1. Tutorial Overview In this tutorial, you re going to create a very simple application on the iphone or ipod Touch. It has a text field, a label, and a button

More information

WORD XP/2002 USER GUIDE. Task- Formatting a Document in Word 2002

WORD XP/2002 USER GUIDE. Task- Formatting a Document in Word 2002 University of Arizona Information Commons Training Page 1 of 21 WORD XP/2002 USER GUIDE Task- Formatting a Document in Word 2002 OBJECTIVES: At the end of this course students will have a basic understanding

More information

Content Author's Reference and Cookbook

Content Author's Reference and Cookbook Sitecore CMS 7.2 Content Author's Reference and Cookbook Rev. 140225 Sitecore CMS 7.2 Content Author's Reference and Cookbook A Conceptual Overview and Practical Guide to Using Sitecore Table of Contents

More information

Forms Desktop for Windows Version 4 Manual

Forms Desktop for Windows Version 4 Manual Forms Desktop for Windows Version 4 Manual Revision Date 12/05/2007 HanDBase is a Registered Trademark of DDH Software, Inc. All information contained in this manual and all software applications mentioned

More information

CREATING ACCESSIBLE SPREADSHEETS IN MICROSOFT EXCEL 2010/13 (WINDOWS) & 2011 (MAC)

CREATING ACCESSIBLE SPREADSHEETS IN MICROSOFT EXCEL 2010/13 (WINDOWS) & 2011 (MAC) CREATING ACCESSIBLE SPREADSHEETS IN MICROSOFT EXCEL 2010/13 (WINDOWS) & 2011 (MAC) Screen readers and Excel Users who are blind rely on software called a screen reader to interact with spreadsheets. Screen

More information

Report Generator for DPOPWR

Report Generator for DPOPWR Online Help Report Generator for DPOPWR Adapted from the Report Generator for DPOPWR Online Help www.tektronix.com Copyright Tektroni x. All rights reserved. Licensed software products are owned by Tektronix

More information

POWERPOINT 2003 OVERVIEW DISCLAIMER:

POWERPOINT 2003 OVERVIEW DISCLAIMER: DISCLAIMER: POWERPOINT 2003 This reference guide is meant for experienced Microsoft Office users. It provides a list of quick tips and shortcuts for familiar features. This guide does NOT replace training

More information

Excel 2013 for Beginners

Excel 2013 for Beginners Excel 2013 for Beginners Class Objective: This class will familiarize you with the basics of using Microsoft Excel. Class Outline: Introduction to Microsoft Excel 2013... 1 Microsoft Excel...2-3 Getting

More information

About your presenter. David Intersimone David I. Vice President of Developer Relations and Chief Evangelist

About your presenter. David Intersimone David I. Vice President of Developer Relations and Chief Evangelist World Tour About your presenter David Intersimone David I Vice President of Developer Relations and Chief Evangelist Email: davidi@embarcadero.com Twitter: davidi99 Blog: blogs.embarcadero.com/davidi/

More information

Creating a Title Block & Border Using Chief Architect. Architectural Design & Residential Construction Penncrest High School

Creating a Title Block & Border Using Chief Architect. Architectural Design & Residential Construction Penncrest High School Creating a Title Block & Border Using Chief Architect Architectural Design & Residential Construction Penncrest High School 2017-2018 Select New Layout to begin designing your Title Block. Note: Once the

More information

Get Started. Estimating Explorer

Get Started. Estimating Explorer Get Started Estimating Explorer NOTICE This document and the Sage Timberline Office software may be used only in accordance with the accompanying Sage Timberline Office End User License Agreement. You

More information

NiceLabel Designer Standard User Guide

NiceLabel Designer Standard User Guide NiceLabel Designer Standard User Guide English Edition Rev-1112 2012 Euro Plus d.o.o. All rights reserved. Euro Plus d.o.o. Poslovna cona A 2 SI-4208 Šenčur, Slovenia tel.: +386 4 280 50 00 fax: +386 4

More information

L E S S O N 2 Background

L E S S O N 2 Background Flight, Naperville Central High School, Naperville, Ill. No hard hat needed in the InDesign work area Once you learn the concepts of good page design, and you learn how to use InDesign, you are limited

More information

USER MANUAL Page 0 of 107

USER MANUAL Page 0 of 107 USER MANUAL 7.1 www.dgflick.com Page 0 of 107 Table of Contents 1.0. Introduction... 3 2.0. System Requirements... 4 3.0. Opening the Tool Box Getting Started... 5 3.1. Registration... 6 3.1.1. Online

More information

Microsoft Office Publisher

Microsoft Office Publisher Microsoft Office 2007- Publisher Opening Microsoft Publisher Using the Start Menu, click on All Programs and navigate to the Microsoft Office folder. Click on Microsoft Office Publisher 2007. Choosing

More information

Excel 2016 Basics for Windows

Excel 2016 Basics for Windows Excel 2016 Basics for Windows Excel 2016 Basics for Windows Training Objective To learn the tools and features to get started using Excel 2016 more efficiently and effectively. What you can expect to learn

More information

FactoryLink 7. Version 7.0. Client Builder Reference Manual

FactoryLink 7. Version 7.0. Client Builder Reference Manual FactoryLink 7 Version 7.0 Client Builder Reference Manual Copyright 2000 United States Data Corporation. All rights reserved. NOTICE: The information contained in this document (and other media provided

More information

All textures produced with Texture Maker. Not Applicable. Beginner.

All textures produced with Texture Maker. Not Applicable. Beginner. Tutorial for Texture Maker 2.8 or above. Note:- Texture Maker is a texture creation tool by Tobias Reichert. For further product information please visit the official site at http://www.texturemaker.com

More information

Page Gentics Software GmbH Enterprise Portals and Content Management Systems

Page Gentics Software GmbH Enterprise Portals and Content Management Systems 1. 2012 Gentics Software GmbH Page 2 Table of Contents 1. Table of Contents... 3 2. Foreword Infoportal and Support... 6 3. First steps... 6 3.1 Login and logout... 6 3.2 Password change... 7 3.3 User

More information

Bombardier Business Aircraft Customer Services. Technical Publications. SmartPubs Viewer 3.0 User Guide. Updated January 2013 [2013]

Bombardier Business Aircraft Customer Services. Technical Publications. SmartPubs Viewer 3.0 User Guide. Updated January 2013 [2013] Bombardier Business Aircraft Customer Services Technical Publications SmartPubs Viewer 3.0 User Guide Updated January 2013 [2013] Table of Contents Application Views... 5 Collection View... 5 Manual View...

More information

Numbers Basics Website:

Numbers Basics Website: Website: http://etc.usf.edu/te/ Numbers is Apple's new spreadsheet application. It is installed as part of the iwork suite, which also includes the word processing program Pages and the presentation program

More information

User Guide Belltech Systems, LLC

User Guide Belltech Systems, LLC User Guide Belltech Systems, LLC http://www.belltechsystems.com May, 2006 1. Introducing Belltech CaptureXT 2. Installation and Uninstallation Installation Running the Application Uninstallation 3. User

More information

Poster-making 101 for 1 PowerPoint slide

Poster-making 101 for 1 PowerPoint slide Poster-making 101 for 1 PowerPoint slide Essential information for preparing a poster for the poster printer 1. Poster size: You will be creating a single large slide in PowerPoint. 2. Before adding any

More information

Section 4 Working with Text

Section 4 Working with Text ECDL Section 4 Working with Text Section 4 Working with Text By the end of this section you should be able to: Start and close the WordPad program Recognise common program features Create text-based documents

More information

Lesson 6 Adding Graphics

Lesson 6 Adding Graphics Lesson 6 Adding Graphics Inserting Graphics Images Graphics files (pictures, drawings, and other images) can be inserted into documents, or into frames within documents. They can either be embedded or

More information

Quick Access Toolbar. You click on it to see these options: New, Open, Save, Save As, Print, Prepare, Send, Publish and Close.

Quick Access Toolbar. You click on it to see these options: New, Open, Save, Save As, Print, Prepare, Send, Publish and Close. Opening Microsoft Word 2007 in the practical room UNIT-III 1 KNREDDY 1. Nyelvi beállítások az Office 2007-hez (Language settings for Office 2007 (not 2003)) English. 2. Double click on the Word 2007 icon

More information

Microsoft Word 2010 Tutorial

Microsoft Word 2010 Tutorial 1 Microsoft Word 2010 Tutorial Microsoft Word 2010 is a word-processing program, designed to help you create professional-quality documents. With the finest documentformatting tools, Word helps you organize

More information

Microsoft PowerPoint 2003 Basic Activities

Microsoft PowerPoint 2003 Basic Activities Microsoft PowerPoint 2003 Basic Activities Activity 1 Creating a new blank presentation... 1 1A. Applying Layouts... 1 1B. Applying a Slide Design... 1 1C. Applying a Background... 2 1D. Entering Text...

More information

Microsoft Word 2007 on Windows

Microsoft Word 2007 on Windows 1 Microsoft Word 2007 on Windows Word is a very popular text formatting and editing program. It is the standard for writing papers and other documents. This tutorial and quick start guide will help you

More information

A QUICK TOUR OF ADOBE ILLUSTRATOR CC (2018 RELEASE)

A QUICK TOUR OF ADOBE ILLUSTRATOR CC (2018 RELEASE) A QUICK TOUR OF ADOBE ILLUSTRATOR CC (2018 RELEASE) Lesson overview In this interactive demonstration of Adobe Illustrator CC (2018 release), you ll get an overview of the main features of the application.

More information

Software User's Guide

Software User's Guide Software User's Guide The contents of this guide and the specifications of this product are subject to change without notice. Brother reserves the right to make changes without notice in the specifications

More information

The Fundamentals. Document Basics

The Fundamentals. Document Basics 3 The Fundamentals Opening a Program... 3 Similarities in All Programs... 3 It's On Now What?...4 Making things easier to see.. 4 Adjusting Text Size.....4 My Computer. 4 Control Panel... 5 Accessibility

More information

Here is a step-by-step guide to creating a custom toolbar with text

Here is a step-by-step guide to creating a custom toolbar with text How to Create a Vertical Toolbar with Text Buttons to Access Your Favorite Folders, Templates and Files 2007-2017 by Barry MacDonnell. All Rights Reserved. Visit http://wptoolbox.com. The following is

More information

W-E

W-E Signage Suite V2.20 User Guide 605220-02-01-W-E-051613-02 Trademarks Windows XP, Windows Vista, Windows 7, and Microsoft are registered trademarks of Microsoft Corporation. All other trademarks are the

More information

Microsoft PowerPoint 2013 Beginning

Microsoft PowerPoint 2013 Beginning Microsoft PowerPoint 2013 Beginning PowerPoint Presentations on the Web... 2 Starting PowerPoint... 2 Opening a Presentation... 2 File Tab... 3 Quick Access Toolbar... 3 The Ribbon... 4 Keyboard Shortcuts...

More information

Using Sitecore 5.3.1

Using Sitecore 5.3.1 Using Sitecore 5.3.1 An End-User s Guide to Using and Administrating Sitecore Author: Sitecore Corporation Date: December 12, 2007 Release: Rev. 1.0 Language: English Sitecore is a registered trademark.

More information

GUARD1 PLUS Documentation. Version TimeKeeping Systems, Inc. GUARD1 PLUS and THE PIPE are registered trademarks

GUARD1 PLUS Documentation. Version TimeKeeping Systems, Inc. GUARD1 PLUS and THE PIPE are registered trademarks GUARD1 PLUS Documentation Version 3.02 2000-2005 TimeKeeping Systems, Inc. GUARD1 PLUS and THE PIPE are registered trademarks i of TimeKeeping Systems, Inc. Table of Contents Welcome to Guard1 Plus...

More information

Contents. Launching Word

Contents. Launching Word Using Microsoft Office 2007 Introduction to Word Handout INFORMATION TECHNOLOGY SERVICES California State University, Los Angeles Version 1.0 Winter 2009 Contents Launching Word 2007... 3 Working with

More information

Introduction. Watch the video below to learn more about getting started with PowerPoint. Getting to know PowerPoint

Introduction. Watch the video below to learn more about getting started with PowerPoint. Getting to know PowerPoint PowerPoint 2016 Getting Started With PowerPoint Introduction PowerPoint is a presentation program that allows you to create dynamic slide presentations. These presentations can include animation, narration,

More information