Discover Fire Monkey Whitepaper by Marco Cantu

55
Americas Headquarters EMEA Headquarters Asia-Pacific Headquarters 100 California Street, 12th Floor San Francisco, California 94111 York House 18 York Road Maidenhead, Berkshire SL6 1SF, United Kingdom L7. 313 La Trobe Street Melbourne VIC 3000 Australia Discover FireMonkey, The Next Generation Business Application Platform Marco Cantù, http://blog.marcocantu.com October 2011

Transcript of Discover Fire Monkey Whitepaper by Marco Cantu

Page 1: Discover Fire Monkey Whitepaper by Marco Cantu

Americas Headquarters

EMEA Headquarters

Asia-Pacific Headquarters 100 California Street, 12th Floor San Francisco, California 94111

York House 18 York Road Maidenhead, Berkshire SL6 1SF, United Kingdom

L7. 313 La Trobe Street Melbourne VIC 3000 Australia

Discover FireMonkey, The Next Generation Business Application Platform

Marco Cantù, http://blog.marcocantu.com

October 2011

Page 2: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 1 -

EXECUTIVE SUMMARY FireMonkey is a brand new application platform for building stunning visual applications in Delphi and C++Builder. FireMonkey uses native graphics libraries to abstract from the underlying OS. It offers powerful HD (High Definition) and 3D graphics, flexible styles, support for rich GUIs, and a new data binding model for business applications. In this whitepaper, I will introduce you to FireMonkey and guide you through its key features while building simple real-world applications for Windows, Mac, and iOS.

The whitepaper, which is meant for developers already familiar with Delphi or C++Builder, will help you get started and understand the role of the various technologies that are part of FireMonkey, while building business applications. We will also see how you can connect to data from a database, a middle-tier DataSnap server (also built in Delphi), or a cloud-hosted database. Overall, I am going to touch on a number of different technologies, because FireMonkey is not simply a collection of components, but a sophisticated framework providing a foundation for the future of Embarcadero RAD Studio. In fact, while VCL will continue as a Windows-only library, FireMonkey is at the core of the new cross-platform architecture of Delphi and C++Builder, along with native compilers for different operating systems.

Notice that differently from other frameworks, FireMonkey applications are native applications on each platform. Native to the CPU because the application source code is compiled and native to the GPU because rendering code is compiled as well. This is a very important feature at the core of the FireMonkey library.

AN INTRODUCTION TO FIREMONKEY So what does FireMonkey mean to a Delphi or C++Builder developer? FireMonkey is a CPU/GPU powered application platform for businesses, enabling developers to rapidly build visually engaging, data rich HD and 3D applications.

FIREMONKEY AS AN APPLICATION PLATFORM FireMonkey as an application development platform is based on a very different model, which offers at the same time abstract user interfaces and native experiences:

• An “abstract” application platform. In the past, there have been user interface libraries that would map to the corresponding elements of the underlying operating system. In Delphi’s VCL, for example, a “TButton” component wraps a Windows button control. FireMonkey, instead, has an abstract notion of a button, and can

Page 3: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 2 -

apply different styles to it to make it look like the native element of different platforms, or go for a totally custom user interface style.

• A “native” platform. Different from other libraries that abstract the user interface, FireMonkey is bound directly to native graphics libraries, like OpenGL or DirectX, offering the best possible performance in terms of using the GPU or the target computer. Also, compared to any other current solution, the code of your application is native, compiled to the CPU. This also means that you have the ability to call native APIs on a given platform. Furthermore, you do not need to distribute or install additional libraries on the target computer, as you can build a single executable, which includes both your code and the required library code. This largely simplifies the deployment, compared to most other similar solutions.

FIREMONKEY AS A COMPONENT-BASED LIBRARY The core of the FireMonkey architecture is the successful and extremely powerful Delphi component library, which has also been available with VCL. FireMonkey also offers hundreds of drag-and-drop components and includes customizable UI elements with programmable animation and effects that can also be extended by third parties.

Delphi was the first tool to introduce a RAD (Rapid Application Development) model based on native components with an object-oriented architecture behind the scenes. FireMonkey extends this model which let developers build applications very quickly, to see code changes reflected in the visual designer; connect to databases and other data sources.

To better explain the role of FireMonkey for Delphi and C++Builder developers, let me answer a few key questions about its scope, its connection to business data, the need for HD graphics, and the flexibility of the platform:

• FireMonkey is great for building user interfaces, but what about access to the file system, calling Web Services, or any other capability of a modern development environment? Well, the answer is very simple: Delphi and C++Builder can already do that using the large collection of classes of their Run Time Library, Azure and Amazon cloud support, SOAP and XML manipulation… well, basically everything that was already in past versions of the RAD Studio libraries is available and it has been extended for cross-platform.

• What about database access? Delphi’s libraries include the dbExpress database independent data access layer and the DataSnap architecture for multi-tier access.

Page 4: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 3 -

The visual controls in FireMonkey can use the brand new LiveBindings architecture to display data coming from many different sources, including database tables. Creating very rich user interfaces driven by data has never been so simple and powerful.

• Why should I need “HD and 3D Graphics”? To create the best looking and most modern applications, you need to stretch the user interface capabilities, and go beyond the limitations of native GUIs. FireMonkey gives you a solid HD structure, but also full support for 3D user interfaces, and the capability of merging both models in a single application.

• But is it “flexible”? Also, given its clean object-oriented and component-based architecture (much like VCL, which was the first of such libraries predating both Java and .NET models), FireMonkey makes it easy to customize the components you interact with, up to the point that you or third party vendors can build custom components to extend the library. And unlike most other solutions, you get the source code of the library to learn the internal tricks and to debug your applications tracing into the library calls.

FIREMONKEY, GRAPHIC LIBRARIES, AND THE GPU As mentioned a few times already, the FireMonkey platform is optimized for the GPU. This does not mean it manages the GPU directly, but that it uses existing libraries (like DirectX or OpenGL) of the various platforms to do graphics processing.

Specifically:

• For HD applications on Windows it uses Direct2D (or GDI+ in case Direct2D is not available)

• For 3D applications on Windows it uses Direct3D

• For HD applications on Mac is uses Quartz

• For 3D applications on Mac it uses OpenGL

• For iOS applications it uses OpenGL

Specifically the GPU is used for 3D, for filters/effects, and for 2D drawing. The GDI+ software fallback is only available for 2D. While a VCL application can generally run on some rather old Windows computers, FireMonkey requires a modern computer with a

Page 5: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 4 -

decent graphics chip (Basic GPU - Any vendor DirectX 9.0 class or better- Pixel Shader Level 2).

If you are not running a FireMonkey application on a native platform, but using a virtual machine or a remote desktop, you might run into issues. Windows 7 and Vista remote desktops should work fine, while WinXP remote desktops should work for 2D but not for 3D. Virtual machine and virtual execution environments (like Citrix) might pose a more significant challenge, as most of them do not support a GPU and not everything in FireMonkey can fall back to GDI+. This is not a FireMonkey specific issue, as other application platforms suffer the same problems.

FIREMONKEY APPLICATION TYPES After this introduction, you might wonder which kind of applications you can use FireMonkey for. The short answer is that FireMonkey can be used in many different scenarios. In fact, the library, along with the existing Delphi RTL and database connection components, can be used for building:

• Standalone applications and utilities with advanced graphical capabilities you can deploy on multiple platforms.

• High-end 3D graphical applications optimized for the GPU.

• Client/server business applications with an advanced user interface (and again the possibility to deploy both on Windows and Mac OS X platforms).

• Both the server side and the client side of multi-tier applications. While the server side might not have a user interface, the client could be deployed on multiple operating systems and phone platforms.

• Native phone apps for iOS with support for other mobile OS platforms in the future

FIREMONKEY VS. OTHER UI LIBRARIES FireMonkey is not the first and only library using the GPU for creating an abstract and optimized user-interface experience. There are RIA platforms that are being used for Web development but also as standalone platforms. Commonly used RIA platforms include Microsoft’s WPF and Silverlight (which have different roles but share a common architecture) and Adobe’s Flex. It might be worth asking ourselves how FireMonkey compares with these platforms.

Page 6: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 5 -

There are, of course, common features, like the complete abstraction from the platform native user-interface controls, and Silverlight/WPF uses the GPU in a way similar to FireMonkey. Also the definition of the UI in a separate file and the use of external styles, also used to adapt the abstract UI to the specific platforms is a common trait, even if the implementation is quite different.

The most significant differences are in the core underlying platform. For Silverlight/WPF the core platform is .NET. This is a managed platform available only on limited operating systems (Windows and Windows Phone, if we don’t include the cross-platform Mono engine, which doesn’t actually support WPF). While the entire .NET library is huge to install, it is widely available on recent versions of Windows. Silverlight has a smaller footprint, but you still need to install it on the target PC (and in the version the application is based on). A significant problem of WPF applications is their start-up time, also due to the Just-In-Time compiler technology .NET is based on.

The Flex platform is based on its custom runtime, available on many platforms, except on iOS. This is a typical scripting environment, with slower execution time than most compiled languages, and limited in the code architecture. While in terms of graphic, Flash and Flex have been favored by the graphic designer’s community, code developers have been far from enthusiastic about adopting this platform, generally favoring the clean architecture of .NET.

FireMonkey departs from these platforms on a few key points:

• First, the code is compiled and native to the CPU and to the operating system. There is no runtime, interpreter, JITter, or anything like that. Just plain compiled code, very fast to execute.

• Second, there is no library to deploy or install. The FireMonkey platform is compiled into the actual application, making it extremely easy to deliver your applications on end-users’ computers and devices, with no limitation (both from a technical point of view and a political one).

• Third, the FireMonkey platform can be adapted to different GPU libraries, like DirectX and OpenGL, and it could be ported to many different operating systems, provided there is a Delphi language compiler for it. While the first version of FireMonkey supports Win32, Win64, Mac OSX, and iOS, in the future Embarcadero plans to port it to several other platforms. Being cross-platform is in FireMonkey’s nature, from the ground up, and unlike other players, Embarcadero has no hidden platform agenda and is more likely to port the platform to additional operating systems..

Page 7: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 6 -

To summarize, FireMonkey offers maximum CPU and GPU performance in a truly cross-platform and open environment, with compiled and native applications, and with no need to install a virtual machine, interpreter, or runtime on the user’s computers and devices. FireMonkey native and optimized rich business applications are already running on Windows, Mac OS, iPad/iPhone hardware and will possibly run on a variety of operating systems quite soon.

THE “BUILD YOUR PIZZA, 101” DEMO So it is now time to start looking to the development of some actual examples. All of the demos of this whitepaper share a common scenario, that of a pizza shop, which has some standard kinds of pizza, but lets you also create your own pizza by picking individual toppings. The pizza shop wants to show menus, accept orders, and let you customize the pizza. We’ll see how FireMonkey will help you in building these applications.

I will start with a very simple application that I will later extend in different ways. The initial version is not much more than the classic Delphi 101 demo with an edit control, a button, and a list box. However, the edit is for you to enter the toppings and the list box shows the list of ingredients of your pizza.

BUILDING THE PIZZA APPLICATION Here are the initial steps for building this application:

1. Use the File | New menu item of the IDE and select Select “FireMonkey HD Application- Delphi” or “FireMonkey HD Application-C++Builder”. For this example, we will select “FireMonkey HD Application- Delphi”. You’ll see a form designer quite similar to the VCL form designer.

2. Now go to the Tool Palette, open the “Standard” category, and pick the following three components: Edit, Button, ListBox. Place each of them on the form. Arrange them like the image in Figure 1.

Page 8: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 7 -

Figure 1: The initial FireMonkey user interface of the demo, before doing any change to the controls

3. To customize this form a little bit, we can change some of the properties of the components (like the caption of the button and that of the main form). While the form has the familiar “Caption” property, to change the caption of the Button you have to use its “Text” property, which is not what a Delphi VCL developer would expect, but something more in line with other frameworks. I have also renamed the form and the various components to make the code easier to read.

What is very similar to VCL is that the various properties you set are saved in a specific form description file and don’t generate source code. This file is similar to the DFM file of a VCL application, but has the FMX extension, which is specific to FireMonkey. To see it, right click on the form in the designer and pick the “View as Text” menu item.

Here is the content of my FireMonkey (FMX) file, in which I have removed some less important properties but left all that show a difference from its DFM counterpart:

object PizzaForm: TPizzaForm Caption = 'Build My Pizza, 101' Transparency = False Visible = False StyleLookup = 'backgroundstyle' object lbToppings: TListBox Position.Point = '(256,32)' Width = 305.000000000000000000 Height = 289.000000000000000000 TabOrder = 2

Page 9: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 8 -

end object edTopping: TEdit Position.Point = '(24,32)' Width = 201.000000000000000000 Height = 22.000000000000000000 TabOrder = 0 ReadOnly = False Password = False end object btnAddTopping: TButton Position.Point = '(24,72)' Width = 201.000000000000000000 Height = 22.000000000000000000 OnClick = btnAddToppingClick TabOrder = 1 StaysPressed = False IsPressed = False Text = 'Add Topping' end end

For everyone with some Delphi or C++Builder experience the differences should be quite obvious and striking. The “Left” and “Top” properties are replaced by a “Position” property, which is a point with two coordinates; “Width” and “Height” properties use floating point values, the form has a “Transparency” property and there is a “StyleLookup” property describing its style, and much more… all within very few lines of very simple code.

As an aside, coordinates in FireMonkey work much like in VCL, with X increasing to the right, Y increasing downwards, and Z increasing away from the screen. FireMonkey uses an abstract coordinate system that is mapped to that of the underlying graphics library (for example, OpenGL has the Y axis increasing upwards, but we don’t have to worry and can just use FireMonkey’s rules).

As you can see above, there is also an event handler attached to the button, a familiar “OnClick” event handler. The event handler has the following code to add the content of the edit control to the list box:

procedure TPizzaForm.btnAddToppingClick(Sender: TObject); begin lbToppings.Items.Add(edTopping.Text); end;

THE C++ VERSION Now this should be extremely familiar, because it is exactly the same code you would write in VCL and was used to demonstrate Delphi 1 back in 1995. Of course, you can also write very similar code in C++Builder:

void __fastcall TForm1::btnAddToppingClick(TObject *Sender)

Page 10: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 9 -

{ lbToppings->Items->Add(edTopping->Text); }

The resulting program running on Windows, as seen in Figure 2, shows the ingredients for a classic Pizza Margherita.

Figure 2: The Pizza building application, running on Windows

At first glance, this application appears very similar to a VCL application without any obvious differences. However, this is actually a very different program both in terms of cross-platform support and of user interface features. Let me start with cross-platform.

BUILD YOUR PIZZA ON A MAC To make our application cross-platform, we can select a new target platform in the Project Manager. Just select the “Target Platforms” node, activate the local menu, and select the only menu item, “Add Platform” (Figure 3, left side), then in the following dialog box, pick the “OS X” platform (Figure 3, right side):

Page 11: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 10 -

Figure 3: To add the “OS X” Mac platform to an existing Delphi project, select the “Add Platform” command in the Project Manager, then pick the given platform in the following

“Select Platform” dialog box.

The next step, if you have not already done so, is to configure the IDE for deploying and debugging the program on a Mac. For this step, you first need to install the “Platform Assistant” application on the target computer, and start it there. The “Platform Assistant” is available from the RAD Studio XE2 installation directory. This tool extends the RAD Studio IDE to the target platform, allowing you to automatically deploy an application on it and run in under the debugger. To accomplish this, the deployment includes the application but also a large file with symbolic information (this file has the RSM extension).

What you can do in the Project Manager is to assign a “remote profile” to the target platform, a profile you can later modify in the Environment Options, as you can see in Figure 4:

Page 12: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 11 -

Figure 4: Configuring a Remote profile for OS X deployment and debugging

With my new profile configuration and the Platform Assistant running on my Mac, I can simply select the platform, click the familiar Run button in the IDE or press the classic F9 key, and the program will run on my Mac (see Figure 5):

Page 13: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 12 -

Figure 5: The Pizza building application running on a Mac Mini

The Mac application behaves exactly as its Windows counterpart, although with the look-and-feel of the the Mac platform. There are other techniques you can use to adapt the application to the platform, rather than having a common user interface across platforms, but this is a more advanced topic than I can cover now.

TOPPINGS TO IOS Now that we have seen how the RAD Studio IDE can cross-compile (and even cross-debug) your application on Mac OS X, we can move to a different type of multi-platform support available for FireMonkey. We will build an application for iOS, the operating system of Apple’s most recent devices: iPod, iPhone, and iPad.

In this case, we cannot just recompile an existing application, but we rather have to create a new project with different settings. The starting point is to open the New Items dialog box of the RAD Studio IDE and pick “FireMonkey HD iOS Application” (notice this is available only for Delphi, not for C++).

The design time form will have a different border to reflect the device it is going to be deployed to. By default the size reflects the iPhone size, but you can adjust it to the size of other iOS devices. Now after adding the usual edit box, button, and list box to the form,

Page 14: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 13 -

you can adjust their visual appearance (picking larger fonts, adjust position to fully utilize the iOS device’s available space) to look like Figure 6 on the left. Add the usual code for the button’s OnClick event handler, and we can run a local instance of the application, as seen in Figure 6 on the right.

Figure 6: The iOS designer in the Delphi IDE (on the left) and a local version of the application running on Windows (on the right)

The running application is not being executed in an iOS emulator, as that is only available in the Xcode development platform on the Mac. This is a FireMonkey Windows application using a different form size, which can still be useful for some initial local testing and debugging.

How do we compile this as an iOS program? To make this easier, the RAD Studio IDE provides the iOS FireMonkey tools, which you install separately from the product install. A one-time setup is performed on the development Mac, in addition to the standard Xcode installation. The FireMonkey-iOS.dmg disk image file installed with RAD Studio under the

Page 15: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 14 -

FireMonkey-iOS directory should be transferred to the Mac. Open it and run the two installer packages inside:

1. fpc-2.4.4.intel-macosx.pkg installs Free Pascal 2.4.4 under /usr/local/. 2. FireMonkey-iOS-XE2.pkg.

- copies Free Pascal 2.5.1 source to /Developer/Embarcadero/fpc/ - copies FMI source required for apps to /Developer/Embarcadero/fmi/ - builds and installs Free Pascal 2.5.1 under /usr/local/ - generates, builds, and installs required iOS SDK headers under

/Developer/Embarcadero/fpc/

This installs and configures your Mac correctly for the external open source compiler (FPC, Free Pascal Compiler) and the FMI (FireMonkey library, the FMX library ported for iOS).

For detailed installation instructions, see: http://docwiki.embarcadero.com/RADStudio/XE2/en/FireMonkey_Platform_Prerequisites#iOS_Development_Setup

The first step we need to do is to run the “Export Project to Xcode” utility (alternatively, the command-line program dpr2xcode.exe is available in RAD Studio XE2 “bin” folder). This will create an Xcode compatible project file. This process only needs to be executed again if the project structure changes, for example, because you have added some new units to your project.

Page 16: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 15 -

Figure 7: The source code of the PizzaToppings application in Xcode (on the Mac)

Now we can move to the Mac, run Xcode, and locate the project (which should likely be on a shared folder, so that you can easily work in the IDE, save your changes, and recompile in Xcode). As you open the project in Xcode (see Figure 7) you can open the various files and edit them, although it is recommended to edit the source in the RAD Studio IDE. You can also pick a device or one of the available simulators as a target. For this demo, I have selected the iPhone simulator.

Now build and run the program (a much slower operation, compared to RAD Studio), and you will see the “PizzaToppings” FireMonkey project written in Delphi running in the actual iPhone simulator on the Mac, as shown in Figure 8.

Page 17: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 16 -

Figure 8: The “PizzaToppings” application running in the iPhone emulator, after compiling it with Xcode on a Mac. This is a Delphi FireMonkey application.

While moving a Delphi application to iOS can be a lot of fun, you have to consider what is available on the platform. Since the compiler used in Xcode is FreePascal, you must use the language features available in FreePascal (which lacks some of the recent extensions to the Delphi language) and run time library that comes with that compiler. What you get on both environments is the FireMonkey application platform, with the exclusion of things that don't make sense or don't exist on iOS, like an Open Dialog.

USING FIREMONKEY EFFECTS AND STYLES Up to now, I have built a very simple application, with plain and classic user interface controls for multiple platforms and using different languages. Of course, the power of FireMonkey is not in delivering a standard user interface to multiple platforms, but rather

Page 18: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 17 -

to deliver to these platforms a rich user experience. That’s what I’ll start exploring in this section.

The goal, of course, is not to build the best possible user interface, but to guide you step by step to understand some of the key features of FireMonkey while building a nice looking interface.

PIZZA TOPPINGS WITH EFFECTS As I mentioned earlier, the first difference between FireMonkey and VCL is the cross-platform support. The second major differentiator compared to a classic Delphi VCL application is that you can customize the user interface using many new techniques.

The simplest one is to attach some predefined effect to the user interface controls. For example, we can add a shadow effect to a button simply selecting a “ShadowEffect” component and dragging it over the button. The button will have a fully configurable shadow, as this effect has a number of properties. The properties used in the demo are:

object ShadowEffect1: TShadowEffect Distance = 3.000000000000000000 Direction = 45.000000000000000000 Softness = 0.300000011920929000 Opacity = 0.600000023841857900 ShadowColor = claBlack End

That translates to a shadow at a 3 pixels distance, a 45 degrees angle, and a given color, opacity, and softness. For the edit box I used a ReflectionEffect component, while I dragged a “CrumpleTransitionEffect” to the list box - like if the list was written on a slightly “crumpled” piece of paper.

You can see the design time form with these effects in Figure 9. Notice that there is another significant difference from VCL. Since any control is automatically a control container, you can add other controls inside it. This is true for a button, which can host other internal controls. And it is also true for list box items: each of them is an individual sub control and can host other controls. Here I have added a “tomato” item, and added an image with an X symbol to remove it. The parent control of this image is the list box item itself, as you can see in the Structure View:

Page 19: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 18 -

Figure 9: The design time structure of a more complex version of the “Build My Pizza” application, with several effects and an image inside a list box item.

When you look at the Structure View inside Figure 9, you can notice another significant feature of FireMonkey that was not available in VCL. I have added a ScaledLayout control to the form, aligned to the client area, and I have added all other controls to it rather than to the form itself. This results in an application that can automatically scale all of its controls as you resize the main form. So you could run two instances of this program, enlarge one and shrink the other, and you’ll be able to obtain an image like in Figure 10.

Figure 10: If you resize the main form of the Build My Pizza application, it will size its internal components to the same ratio. Here are a large and a small version.

Page 20: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 19 -

This behavior is obtained without writing any code. Next, we need to implement the removal of the first item of the list box when the image with the X is pressed:

lbToppings.Items.Delete(0);

The other new button, Crumple, enhances this effect by changing the transition “Progress”. This is a value that goes from 0 to 100, indicating a percentage (the image gets really crumpled above 50 percent):

CrumpleTransitionEffect1.Progress := CrumpleTransitionEffect1.Progress + 1;

These two lines plus the one used to add the content of the edit box to the list is all the code of the application, which, as you can guess, runs also on a Mac (in this case I have enhanced the crumple effect) as you can see in Figure 11.

Figure 11: A very crumpled version of the list of toppings, running on a Mac.

Page 21: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 20 -

BUILD MY PIZZA WITH STYLE I have already introduced a couple of graphical features of FireMonkey, like effects and layout, but this library is extremely rich, so in this section, I will further enhance the application to take advantage of many other features. I will introduce style customizations, animations, items customization, and some of the binding features. While this section is not an exhaustive description of any of those techniques, which are quite complex to grasp in full, it should serve as an introduction of some of the FireMonkey HD features. Later on, I will also introduce a simple 3D application.

STYLES IN FIREMONKEY In the next revision of the pizza toppings application I am going to introduce styles. This is one of the core features of FireMonkey, and it deserves a bit of an introduction. The basic idea is that every visual control can be painted in different styles. There are some default styles you can pick and that partially depend on the target platform. But you can also define custom styles, and you can do so in multiple ways.

When you pick a style, you are not picking a different set of colors or lines: you can really change the individual elements making up a control. For example, a button has a couple of rectangles and a text element, as you can see by opening the default button style in the Style Editor (see Figure 12):

Figure 12: The graphical elements making up a standard button

In other words, the style of a control in FireMonkey is actually a collection of primitive elements, like shapes, effects, backgrounds and textual elements. This means we can add

Page 22: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 21 -

new elements to the style, for example an image to turn a plain button into one with an image (like a VCL BitBtn control).

The simplest way to customize a control is to select an existing style for it. Of course, you should generally pick a button style for a button, or you will alter the control’s behavior significantly. You can also create a new custom style.

One approach to style customization is to implement a new complete set of graphical primitives the controls use for painting, so that you actually generate a new complete style (a technique often referred to as “skinning”). This is quite complex and out of the scope for this paper.

The second approach is to customize the layout of an individual control (an instance) or the default layout of all the controls of a given type within an application. In both cases, this customization is performed using the Style Editor right in the RAD Studio IDE. This is the technique I will focus on in the next example.

In this second approach, customizing a style involves picking some predefined settings for the control’s properties, but also changing its shape by using another control as a base element. Another very specific feature is the ability of adding sub-controls. For example, you can define a style for a button that includes an image. Once you’ve given this style a name, any other button using the same style will have also an image control inside itself, and the ability to become a graphical button.

This ability of creating nested controls with styles is a very significant element of FireMonkey architecture. While FireMonkey has a very rich set of controls, you can expand it infinitely simply by combining the controls with the available styles and also through freely nesting the controls.

A STYLE FOR THE BUTTON As an example of using styles, I am going to take the original version of the ‘Build My Pizza’ example (before I added effects) and use styles (and animations) to customize it. I will also add new controls to the user interface and make the list of toppings look much better. But let me go one step at a time to better explain these steps to you.

I want to start by changing the the fist button of the application by modifying the button style. In order to transform it into a circular button, I selected the control, right-clicked on it, picked the Edit Custom Style menu item, opening the styles editor (displayed later in Figure 14). In this editor, you can see the elements making up the button (under the style “btnAddToppingStyle1”), including three rectangles, some effects, the button's text (having a TText element with the StyleName set to “text” is compulsory for a button style).

Page 23: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 22 -

To make the button look almost circular I set the XRadius and YRadius properties of each of the three rectangles to 55 (given that the width and height of the control will be set to 110). Now the button will change its user interface quite significantly, becoming a round button, as you can see in Figure 13.

Figure 13: A FireMonkey round button at design time, along with the other controls of the PizzaToppingsStyle application.

The more complex the user interface control, the more flexibility you have in customizing it. Rather than working on the angles of the rectangles, I could have created a completely custom style with ellipses. But I have decided for different customizations.

In this revision of the demo, I have replaced the edit for entering the pizza toppings with a “combo edit” control that can be used for selecting an item from a predefined list, while still letting the user enter a custom spice or ingredient (hoping the Pizza Shop has it!).

Notice that the plain combo box in FireMonkey can be used only to select items from the drop down list, while the companion combo edit controls has both selection and editing capabilities. What you achieve in VCL by replacing a setting of the control (mapped to a specific behavior of the operating system), you can achieve here by picking a modified control. Now, before you ask, the reason is that modified controls likely have a very specific style including the edit element, thus the need for separating the two controls rather than having a setting.

Page 24: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 23 -

There we have our basic combo edit box. However, we want the program to show an image for the topping in our list, so we will do further modification to load a JPG image of our topping from the executable file’s folder.

STYLING THE LIST BOX WITH SUB-CONTROLS If creating a custom style means the ability to customize an individual component, then it is even more interesting to note that you can apply the same style to multiple controls, or to multiple sub-elements of a given control. A classic example is using a style to customize the items of a list box. For this demo, I want to add to the list box elements both a descriptive text (the topping name) and an image (if available).

To accomplish this, I have first created a separate style, not by customizing a component but rather as a separate element (obtained by adding a StyleBook component to the form), with the “StyleName” property set to “imagelabel”, as you can see in Figure 14. In the style I’ve also picked a larger font for the text.

Figure 14: A custom style for list box items, including an image and some text

Page 25: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 24 -

Notice that styles are saved in a textual format in the FMX file, just like component properties, but converted to a pure string format. Here is the description of the custom style (again with some omissions to avoid a uselessly long listing):

object StyleBook1: TStyleBook Resource.Strings = ( ' object TLayout' ' StyleName = '#39'imagelabel'#39 ' Align = alScale' ' object image: TImage' ' StyleName = '#39'image'#39 ' end' ' object text: TText' ' StyleName = '#39'text'#39 ' Font.Size = 22.000000000000000000' ' end' ' end' 'end') end

Now in the code I can create a list box item and customize its image and text subcomponents, by referring to the style and the style sub-elements by name:

var listItem: TListBoxItem; itemText: TText; itemImage: TImage; begin // create a new custom listbox item listItem := TListBoxItem.Create(nil); listItem.Parent := listToppings; // force the items style and set the text listItem.Resource := 'imagelabel'; itemText := listItem.FindStyleResource ('text') as TText; if Assigned (itemText) then itemText.Text := strTopping; itemImage := (listItem.FindBinding('image') as TImage); if Assigned (itemImage) then begin itemImage.Bitmap := Image1.Bitmap; listItem.Height := Image1.Bitmap.Height; end else ShowMessage ('Image binding element not found');

For Delphi developers used to VCL, this code should be quite surprising, since you would need a custom control for adding graphical elements to a list! This code, in fact, creates a list box as seen in Figure 15.

Page 26: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 25 -

Figure 15: The graphical list box with the topping names and images at run time

ANIMATIONS: CHANGE PROPERTY VALUES OVER TIME Another key feature available throughout the FireMonkey library is the ability to use an “animated” value rather than a regular one. An “animated” value is a property value that changes over time, from a starting value to a final value, during a given time frame. This “animation” can be triggered in code or take place when a given event occurs, like when a component becomes visible or you move the mouse over it.

As an example, we can make the combo box of the demo enter the form from the side, rather than immediately be visible when the form is displayed. To accomplish this, we select a given property (in this case “Position.X”) at design time, and instead of picking a value we add a TFloatAnimation, which animates a floating point number. Other animations work on colors and gradients, for example. Also, there are different animations that use alternative sequences of values. Animations is a full topic with many avenues to explore. In this demo, however, I will focus on the foundations.

The complete definition of a control that slides in will generally be like this (I’ve omitted some other unrelated properties):

object cbToppings: TComboEdit Position.Point = '(32,24)' Width = 145.00 Height = 22.00 StyleLookup = 'comboeditstyle' object aniSlideInCombo: TFloatAnimation Enabled = True

Page 27: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 26 -

Delay = 0.00 Duration = 0.50 Trigger = 'IsVisible=true' StartValue = -200.00 StopValue = 32.00 PropertyName = 'Position.X' end end

With these design time settings (and no extra code), the combo edit will first appear off-screen because it will be using the starting position value of -200 as defined by the FloatAnimation control. It will then slide into position within half a second. A more sophisticated approach, albeit a slightly more complex one, would be to perform the “Inverse” animation enabling the “StartFromCurrent” property. This way you won’t have to specify the final combo position in the animation, but only in the control itself. A more professional approach could likely use a “fade-in” animation, instead of a “slide-in” one, but here I wanted to focus on a rather simple scenario.

The program uses another custom animation, actually two animations applied to the same control at once. The form has an image control, in which I load the image for the pizza topping as you press the button. The image has a slide animation like the previous one, but also a rotate animation, which goes from 0 to 720 degrees (two complete rounds) to the control rotation angle, saved in the RotationAngle property.

Both animations are programmatically started in the button’s OnClick event handler, which also makes adjustment to one of the animation parameters:

procedure TFormToppings.btnAddClick(Sender: TObject); begin strTopping := cbToppings.ListBox.Selected.Text; Caption := 'Adding ' + strTopping; Image1.Bitmap.LoadFromFile(strTopping + '.jpg'); aniRotateImage.Start; aniMoveImage.StopValue := listToppings.Position.X + 20; aniMoveImage.Start; end;

The pizza topping is added to the list at the end of the animation (which basically moves the image behind the list box, while rotating it), handling its OnFinish event handler, with the code I showed in the previous section. The event handler also clears the image and resets its position.

Page 28: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 27 -

STYLES AND ANIMATIONS ON THE MAC Now that we have extended the application significantly, we can try to move it to the Mac OS X platform to see if it works properly. We also need to figure out how to deploy this application and the external files it used to OS X. This can be done using the Deployment manager.

After adding the OS X platform target to the project, activating it, and compiling it, you can select the Project | Deployment menu command to open the Deployment pane (see Figure 16). This window shows a list of files to deploy to the target platform and we can use the Add Files button to add some images to it.

Figure 16: The deployment pane for the PizzaToppingsStyle project, with the images used by the program

Now we can recompile the application and run it on the Mac. Since the files are available and given that the file access code is operating system independent, everything works smoothly, as you can see in Figure 17.

Page 29: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 28 -

Figure 17: The PizzaToppingsStyle application running on the Mac (during the animation)

BUILDING A 3D PIZZA MENU One of the most powerful areas of FireMonkey, and one of the more challenging ones to approach, is its support for 3D objects and scenes. There are multiple ways to approach the library’s 3D support. One is to consider it as a way to render 3D objects with lights and surfaces of given materials. As an example, you can see the design time and runtime images captured in Figure 18, with a cube and a light source.

Page 30: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 29 -

Figure 18: A FireMonkey 3D example with lights and objects at design time and runtime.

While this can be extremely useful for specific applications, it is not what you will generally use in a business program. A different way of approaching the library’s 3D support, though, is using it for moving and floating bi-dimensional objects like images, videos, and entire 2D forms, in the three-dimensional space. This is what I’m going to demonstrate with the next demo, which is a 3D menu for our Pizza Shop, in which you can literally turn the pages with the available pizzas.

The key difference in this application is the fact that the base class of the main form is now “TForm3D”:

type TFormMenu = class(TForm3D)

The page turning effect is obtained by using two 3D images (that is, images that can float in three dimensions) one in the opposite direction of the other, and turn the two images at the same time using two animations. The algorithm is based on changing the Y value of the Rotation property, using two float animations with the InterpolationBack sequence, so

Page 31: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 30 -

that at the beginning and at the end of the movement there is a limited movement in the opposite direction, like with a real world page movement.

As you can see in the code below, the second image is turned by 180 degrees, and its animation is also shifted:

object Image3D1: TImage3D Width = 500.00 Height = 350.00 Depth = 0.0099 Opacity = 1.00 Projection = pjScreen TwoSide = False OnClick = TurnPage Align = alCenter Quanternion = '(0,0,0,1)' object FloatAnimation1: TFloatAnimation AnimationType = atInOut Enabled = True Duration = 2.00 Interpolation = itBack StartValue = 1.00 StopValue = 179.00 PropertyName = 'RotationAngle.Y' end end object Image3D2: TImage3D RotationAngle.Point = '(0,180,0)' Width = 500.00 Height = 350.00 Depth = 0.0099 Opacity = 1.00 Projection = pjScreen TwoSide = False OnClick = TurnPage Align = alCenter Quanternion = '(0,1,0,-2.71E-20)' object FloatAnimation3: TFloatAnimation AnimationType = atInOut AutoReverse = True Enabled = True Duration = 2.00 Interpolation = itBack StartValue = -180.00 PropertyName = 'RotationAngle.Y' end end

Every time a user clicks on the BufferLayer3D hosting the images or on the images themselves, the following code is executed.

procedure TFormMenu.TurnPage(Sender: TObject); begin LoadNewImage; // in the non-visible 3D image control FloatAnimation1.StartValue := Image3D1.RotationAngle.Y;

Page 32: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 31 -

FloatAnimation1.StopValue := Image3D1.RotationAngle.Y + 180; FloatAnimation3.StartValue := Image3D2.RotationAngle.Y; FloatAnimation3.StopValue := Image3D2.RotationAngle.Y + 180; FloatAnimation1.Start; FloatAnimation3.Start; end;

Finally, you can also animate the right side of the form with a 3D effect, which includes a Layer3D control hosting some regular 2D controls. Using such hosting 3D layer, in fact, is how a standard 2D object can participate in a 3D application. This is the object structure:

object FormMenu: TFormMenu object Layer3D1: TLayer3D object AniIndicator1: TAniIndicator object Panel1: TPanel object Label1: TLabel object Label2: TLabel

To move this control I’m not using design time animation objects, but I’m using methods that define the animations at runtime:

procedure TFormMenu.FlipSide(Sender: TObject); begin Layer3D1.AnimateFloat('RotationAngle.Y', 360, 2, TAnimationType.atInOut, TInterpolationType.itBack); Layer3D1.AnimateFloat('Position.Z', 500, 1); Layer3D1.AnimateFloatDelay('Position.Z', 0, 1, 1); end;

The final effect is partially visible in Figure 19, but you really need to see a video to understand it.

Figure 19: A couple of snapshots of the moving 3D images of the Pizza Menu 3D Demo (although you really have to see a video to appreciate it)

Page 33: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 32 -

DATA AND BINDINGS In the various “Build my Pizza” applications, users could populate a list box with some plain text of graphical data, but the final information was only available in the control itself and not the next time we run the application. What if we want to send it to a database to make it persistent? And what if we want to get the list of available toppings or the list of ready-to-order pizzas from a database, including the price of each?

In contrast to VCL, FireMonkey has no special data-aware version of the controls. That is why Delphi XE2 introduces a new global concept of data binding called LiveBindings, which you can use in both VCL and FireMonkey. The idea is that you can bind a value of an object to a property of a value of a different object, so that the two are kept in sync. In this paper, however, I will not discuss data binding in general, but only focus on binding visual controls to a dataset.

Keep in mind that FireMonkey uses different kinds of bindings. There is data binding (or LiveBindings), which is what I am demonstrating in this section. A different one is style binding, which I have used in the section “Styling the List Box with Sub-Controls” for locating sub-elements of the list box items. A third kind of binding, called “Magic Variant Binding”, lets you connect the value of sub-elements directly (as it happens in the CustomListBox example that ships with the product.)

Again, in this demo, I am focusing on LiveBindings, the mechanism you use to associate user interface elements with database data. The application I am going to build is a simple but complete editor, which could easily be turned into a menu viewer by making the visual controls read-only. The program is called “FmxPizzaMenuDB” and it uses a ClientDataSet with the available pizzas, their descriptions, their prices, and a corresponding image. (In the source code you will also find a VCL version of the same program, based on a DBGrid. This side project is called VCLPizzaMenu.)

Both the FireMonkey and the VCL program start from an existing dataset or you can create an empty one from the data structure defined in the FieldDefs collection of a ClientDataSet component:

object cdsPizzaMenu: TClientDataSet FieldDefs = < item Name = 'Id' DataType = ftInteger end item Name = 'Name' DataType = ftString Size = 36 end item

Page 34: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 33 -

Name = 'Description' DataType = ftString Size = 256 end item Name = 'Price' DataType = ftCurrency end item Name = 'Image' DataType = ftGraphic end> StoreDefs = True End

As usual in Delphi, this application has a DataSource hooked to the dataset, but from this point things are different. By the way, you can see a snapshot in design time of all of the components used in the main form of the application in Figure 20.

Figure 20: The visual controls and the non-visual components of the FmxPizzaMenuDB program at design time in the RAD Studio form editor.

Page 35: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 34 -

The DataSource is referenced from a BindScopeDB component, which is the conduit between the new data binding model and the old data-aware architecture or, to put it in a simpler way, the conduit between data binding and a TDataSet:

// listing: tdata source + bind scope DB object dsPizza: TDataSource DataSet = cdsPizzaMenu end object BindScopeDB1: TBindScopeDB DataSource = dsPizza End

The actual associations take place in a BindingList container, which holds the various data bindings for the current application. You can see the list of bindings I’ve defined in Figure 21.

Figure 21: The Data Bindings Editor

As you can see in Figure 21, the program connects three edit boxes and a memo control to four different fields, plus an ImageControl tied to a graphic field. In the FMX code below you can see that there are three different types of links involved: three instances of the TBindDBEditLink class, one of the TBindDBMemoLink class, and one of the

Page 36: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 35 -

TBindDBImageLink. The binding list definition in the FMX file is long, but it is worth looking at it, since this is the real code of the application:

object BindingsList1: TBindingsList UseAppManager = True object DBEditLinkID: TBindDBEditLink Category = 'DB Links' DataSource = BindScopeDB1 FieldName = 'ID' EditControl = edID end object DBEditLinkName: TBindDBEditLink Category = 'DB Links' DataSource = BindScopeDB1 FieldName = 'Name' EditControl = edName end object DBEditLinkPrice: TBindDBEditLink Category = 'DB Links' DataSource = BindScopeDB1 FieldName = 'Price' EditControl = edPrice end object DBImageLinkImage: TBindDBImageLink Category = 'DB Links' DataSource = BindScopeDB1 FieldName = 'Image' ImageControl = imgImage end object DBMemoLinkDescription: TBindDBMemoLink Category = 'DB Links' DataSource = BindScopeDB1 FieldName = 'Description' MemoControl = meDescription end end

The only additional code required is a line to open the ClientDataSet as the program starts (in the OnCreate event handler of the form), plus the following code to load a new image in the database (which automatically makes it available to the image control tied to the field);

procedure TFormPizzaMenu.btnLoadImageClick(Sender: TObject); begin if OpenDialog1.Execute then begin cdsPizzaMenu.Edit; (cdsPizzaMenu.FieldByName('Image') as TGraphicField). LoadFromFile(OpenDialog1.FileName); cdsPizzaMenu.Post; end; end;

The output of the application looks like that in Figure 22, with a nice pizza Margherita on display. Notice the navigator at the top of the form, a TBindNavigator control (with

Page 37: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 36 -

standard images) that you can fully customize in terms of user interface and in terms of the available actions.

Figure 22: We have Pizza Margherita in the Database

Of course we could do exactly the same with a dataset mapped to a relational database, using dbExpress or any other database access technology available in Delphi. Since these database access components often end up populating a ClientDataSet, the user-interface portion of a similar application will remain the same. We are actually going to see this in a different scenario - the client side of a multi-tier application built with DataSnap.

MULTI-TIER PIZZA The database application I just built uses local data for data source. And as I have mentioned, it can be easily turned into a client/server application talking to a relational database. I am, however, going to skip the client/server step, in order to move to the more complex architecture - the development of a multi-tier application based on the DataSnap technology! This is a multi-tier technology that has been part of Delphi for over 10 years,

Page 38: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 37 -

and was significantly enhanced in the last few versions of the product to fully embrace Internet-based communication by natively supporting TCP/IP, HTTP, and HTTPS. Here I’ll just sketch the steps you have to follow, as an in-depth analysis of DataSnap is beyond the scope of this whitepaper.

First, we have to build a server, this is a Windows application (but could as well be a Windows service or a console program) that you could run on a custom Windows server or deploy to a server “in the cloud”, as I’ll show later in this paper. The server is not tied to FireMonkey and will equally work with different client libraries. In the second step, however, I’ll build a client (modifying the previous example), and it will be a FireMonkey client.

BUILDING A DATASNAP SERVER To build the server, open the File | New | Other dialog box, select the DataSnap page, and pick the “DataSnap Server Application” icon. In the pages you can go for custom settings. However, I picked the HTTP protocol (see Figure 23) and selected port 8090 in the following page. In the last page, I selected TDSServerModule, a base class that will simplify exporting a dataset to the client.

Figure 23: Some of the settings of the DataSnap Server Application.

Page 39: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 38 -

The resulting application will have a few parts: an unnecessary main form (although I will actually use it by adding a list box to it with pending orders from the clients application to show interaction between them); a “server container” data module with the DSHTTPService component, defining the connectivity, plus some other structural DataSnap components; and a “server methods” unit, which is the unit I will customize for this demo.

The steps we have to follow to build this program are quite simple. First, we need to expose a dataset. This is accomplished by adding a dataset component to this last data module. It could be a dataset for accessing a relational database, but for simplicity I will use a local ClientDataSet. The second component we need is a DataSetProvider, which will expose the dataset to the client applications. These are the key properties of the two components:

object DataSetProvider1: TDataSetProvider DataSet = ClientDataSet1 end object ClientDataSet1: TClientDataSet FileName = ‘PizzaMenu.cds' End

This is all it takes to expose a dataset. However, the server has a second feature, a server side method used to accept pizza orders. The client will invoke this method passing the name of the pizza and the customer name (not a real world scenario, but enough to let you understand the approach).

For this second step we need to add a method to the server class, called TServerMethods1 by default (after removing the methods generated by the wizard):

type TServerMethods1 = class(TDSServerModule) ClientDataSet1: TClientDataSet; DataSetProvider1: TDataSetProvider; public function OrderPizza (PizzaName, CustomerName: string): Integer; end;

The OrderPizza method takes two string parameters and returns an integer indicating how many pending orders there are. For this simple demo, the program will add the orders to a list box in the main form, and the user (working on the server) can select the order to process and remove them from the pending list. I will not list the code of this demo, as it is unrelated to FireMonkey, thus not the topic of this whitepaper.

Page 40: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 39 -

BUILDING A FIREMONKEY DATASNAP CLIENT As I have briefly introduced in the previous section, for building a DataSnap server you need a specific architecture. For a DataSnap client, instead, you can create any client application and add support with an extra unit generated by a wizard. Specifically, I’m going use the DataSnap Client Module wizard from the New Items dialog box. You can use this wizard only if the server application is running (and within reach from the development machine).

In the various pages of the wizard you have to do the following:

• In the first page, leave the default option, local server

• In the second page, leave the default option, DataSnap stand alone server

• In the third page, change the selection to HTTP

• In the fourth page, enter 8090 (at least, this is the port I used) and leave everything else as it is (and as visible in Figure 24).

Page 41: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 40 -

Figure 24: You can turn any FireMonkey (or VCL) application into a DataSnap client by using the DataSnap Client Module wizard. Here is the last page of the wizard.

The wizard generates two files, one hosting the client classes (the proxy classes we can use to access server methods) and the other hosting the client module, a data module with a ready to use remote connection component. To access the remote table, we can add a second component to this data module, a DataSnap Provider Connection:

object DSProviderConnection1: TDSProviderConnection ServerClassName = 'TServerMethods1' SQLConnection = SQLConnection1 End

The component refers to the SQLConnection component configured by the wizard to refer to the specific DataSnap server; and to the name of the class of the server we want to refer to, in the example the default 'TServerMethods1'. After adding these new units to the previous example, the database pizza menu, we can modify the main form. Basically, we have to remove the reference to a local file from the ClientDataSet component, and add this initialization code (that I’ve added to the OnClick event handler of a button, rather than on form creation, as in the latter case an error will prevent the program from starting):

procedure TFormPizzaMenu.btnConnectClick(Sender: TObject); begin cdsPizzaMenu.RemoteServer := ClientModule1.DSProviderConnection1; cdsPizzaMenu.ProviderName := 'DataSetProvider1'; cdsPizzaMenu.Open; end;

As you can see in the code above, the ClientDataSet must refer to the provider connection and indicate the specific data table, using the name of the provider component used on the server. The result of running this code is a form similar to the previous version, but now accessing remote data rather than a local file. A sample output is in Figure 25.

Page 42: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 41 -

Figure 25: Pizza data and images now coming from a remote DataSnap server

To finish the DataSnap client, we have to be able to place an order. As the user types in the customer name edit box, the Place Order button gets enabled. Pressing it executes the following code:

procedure TFormPizzaMenu.btnOrderClick(Sender: TObject); var nInLine: Integer; begin nInLine := ClientModule1.ServerMethods1Client.OrderPizza( cdsPizzaMenu.FieldByName('Name').AsString, edCustomerName.Text); ShowMessage ('You are number ' + IntToStr (nInLine) + ' in the line'); end;

The code above refers to the proxy object (ServerMethods1Client) surfaced by the client data module, and calls the OrderPizza method directly, receiving a response, as you can see in Figure 26. Now an animation of the position in the line over time could be a nice addition!

Page 43: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 42 -

Figure 26: The order for the pizza showing up on the server (which, of course, will be running on a different computer).

DATASNAP CLIENT TO THE MAC There are several interesting features in a DataSnap multi-tier architecture, starting with the fact that the database connection and the data access code (and business rules) are centralized. In other words, you do not need to deploy a client library to the end user computer, making the deployment much simpler (basically, a file copy operation).

The other interesting element is that DataSnap is not a Windows-only architecture. You can use the HTTP REST interface for building clients for almost any platform. With Delphi XE2 and FireMonkey, we can recompile and deploy a DataSnap client on the Mac OS X platform without having to change anything in the source code.

In this specific demo, we have to add another element in order to give the ability to specify the hostname or IP address of the server machine. I chose to add an edit box to the main form whose value is passed to a function I have added to the data module before connecting to the server:

procedure TClientModule1.SetIP(const strIP: string);

Page 44: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 43 -

begin SQLConnection1.Params.Values['HostName'] := strIP; end;

Since the program uses the ClientDataSet component, which is implemented in the midas.dll library, we also need to add the corresponding library (libmidas.dylib) to the list of files to deploy. A sample deployment structure is shown in Figure 27:

Figure 27: To deploy a DataSnap client to the Mac you need to include the libmidas.dylib library file.

With the flexible IP and extra file deployed, we can now run the DataSnap client on the Mac (see Figure 28). This is a very significant extension to the DataSnap architecture as a whole.

Page 45: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 44 -

Figure 28: The DataSnap client running on the Mac, with data provided by a DataSnap server running on Windows

A DATASNAP SERVER IN THE CLOUD As a finishing touch, we could easily move this application to a cloud infrastructure. We’ll see in the next section how to build a real cloud-based pizza menu, but the simplest approach would be to deploy the DataSnap server I built earlier to the Amazon EC2 infrastructure or to Azure, and use the proper IP in the client to connect to the proper host.

Notice that there is nothing you have to change in the server source code or the compilation. All you need to do is take the executable file and the data, and deploy them either manually or using the RAD Studio IDE automatic deployment support.

PIZZA IN THE CLOUD Deploying a server to an instance running on Amazon EC2 is technically identical to having the same application running on a custom server or a custom virtual machine of a physical

Page 46: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 45 -

server you own. If we really want to create a truly cloud-based application, we should rather distribute the database data and pizza images to cloud-based storage.

In the next example, I’m going to use Microsoft’s Azure Table and Blob services, but I could have equally used Amazon S3 and simple tables as both services are now well integrated in Delphi.

Delphi includes some components for Azure, but also and moreover a number of lower level classes, which is where the real power is. These classes provide ready-to-use methods for performing the various operations and deal with the complicated security requirements of the Azure platform.

The core non-visual component is the one used to configure the connection to the service, called TAzureConnectionInfo. This component is a handy starting point in which to enter the user name and password of your account. Needless to say you need to have an Azure account (with information added to a separate INI file) to test this demo.

This demo uses a pre-populated non-relational database table with the pizza menu data. I have populated the database using the VCLPizzaMenu application not discussed here, as it does not relate to FireMonkey. However, the code for the application will be included in the companion code part of the whitepaper download.

The client application is not a direct extension to the previous pizza menu program, as we do not have a dataset to bind our user interface to. Still the user interface has similar visual controls, plus a list box with the list of menu entries. The program initialization code is located in the “OnCreate” event of the main form. The code (below) reads the Azure account settings from an INI file in the user’s documents folder and initializes two private fields of the form: TableService and BlobService:

procedure TFormPizzaMenu.FormCreate(Sender: TObject); var fIni: TMemIniFile; begin fIni := TMemIniFile.Create(GetHomePath + PathDelim + 'azure.ini'); try AzureConnectionInfo1.AccountName := fIni.ReadString('azure', 'AccountName', ''); AzureConnectionInfo1.AccountKey := fIni.ReadString('azure', 'AccountKey', ''); finally FreeAndNil (fIni); end; Caption := Caption + ' - ' + AzureConnectionInfo1.TableURL; TableService := TAzureTableService.Create(AzureConnectionInfo1); BlobService := TAzureBlobService.Create(AzureConnectionInfo1); end;

Page 47: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 46 -

By clicking on a button, the program retrieves the list of pizzas in the menu, by reading the two key fields of an Azure table:

procedure TFormPizzaMenu.btnGetListClick(Sender: TObject); var rowsList: TList<TCloudTableRow>; aRow: TCloudTableRow; begin rowsList := TableService.QueryEntities(tablename); try ListBox1.Clear; for aRow in rowsList do begin ListBox1.Items.Add(aRow.GetColumn(XML_ROWKEY).Value + '=' + aRow.GetColumn(XML_PARTITION).Value); end; finally rowsList.Free; end; end;

By the way, I could have kept the table data (rowsList) in memory, rather than fetching the data for each individual entry, but I wanted to show a more complete example. So now we have a list of entries in the list box.

As a user double clicks on an item, the program extracts the row and partition key and uses them as the ID of the individual record (or row) to fetch from the database table. The second step is to get the image from the Blob service, using the partition key name (in this case the record ID) as a file name, since this was the rule I used when uploading those images.

This is the code used to fetch the data and populate the user interface for an individual entry, with the result shown in Figure 29:

procedure TFormPizzaMenu.ListBox1DblClick(Sender: TObject); var aRow: TCloudTableRow; memStream: TMemoryStream; begin // get the data for the current element if Assigned (ListBox1.Selected) then begin aRow := TableService.QueryEntity(tablename, ListBox1.Items.ValueFromIndex [ListBox1.Selected.Index], ListBox1.Items.Names [ListBox1.Selected.Index]); if Assigned (aRow) then begin edId.Text := aRow.GetColumn(XML_PARTITION).Value; edName.Text := aRow.GetColumn(XML_ROWKEY).Value;; meDescription.Text := aRow.GetColumn('description').Value; edPrice.Text := aRow.GetColumn('price').Value; memStream := TMemoryStream.Create; BlobService.GetBlob(tablename,

Page 48: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 47 -

aRow.GetColumn(XML_PARTITION).Value + '.jpg', memStream, ''); memStream.Position := 0; imgImage.Bitmap.LoadFromStream(memStream); MemStream.Free; end; aRow.Free; end; end;

Figure 29: The user interface of the Pizza Menu Cloud application, after fetching one row (or record).

FIREMONKEY FOR EXISTING DELPHI AND VCL

USERS In this whitepaper we have seen a number of features of the new FireMonkey application platform and if you are a Delphi developer you have certainly noticed how different it is from the classic VCL architecture. While all of your Delphi code (algorithms, database access code, cloud services, and more much) will easily port to FireMonkey, the user interface is a little more challenging due to the difference between VCL and FireMonkey. However, user interface really should be recreated to take advantage of the multi-platform support and the rich graphical capabilities in FireMonkey.

Page 49: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 48 -

Some of your VCL code can be ported. Some of the visual controls have a similar role and similar property and method names. For example, some of the initial demos had code identical to that of a VCL application.

There are notable differences, though, even for basic features. For example, control positions are not expressed with “Left” and “Top”, but with a single “Position” property with X and Y sub-values. For 3D objects, however, there is also a Z axis. I mentioned the key elements of the coordinate system in the initial section, “Building The Pizza Application”.

All control positions and sizes are expressed in floating point values, rather than integer ones. The size of fonts uses a different scale, which can cause confusion.

For most FireMonkey controls, the textual information is stored in the Text property, rather than in the Caption property generally used by VCL. The notable exception is the form object, which uses the Caption property in both libraries.

There are other differences I can point out. Rather than continuing with such a list, however, I would rather try to migrate a focused example based on a ListView control.

FOLLOWING PIZZA TWEETS (VCL VERSION) If you have a Pizza Shop, keeping up with news about pizza is also quite a relevant activity. One way to do that, even if a bit “flooding”, is to search Twitter for either the plain word “pizza” or the tag “#pizza”. For this purpose I’ve adapted an existing Twitter client I had to search for a word. The user interface of the VCL version is in Figure 30.

Figure 30: The VCL version of the PizzaTweets application, to be ported to FireMonkey.

Page 50: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 49 -

The application is clearly split into two parts: there is a data processing back-end, implemented using a data module, and the user interface. The data processing is based on a separate data module, which in turn uses Delphi XML interface mapping technology to process the data retrieved by calling the Twitter REST web service. The communication is done using the Indy HTTP client component (IdHTTP) and the XML processing is based on Delphi’s XMLDocument component, which can map different XML engines. At the end, the selected tweets are exported to HTML using a PageProducer component.

The interaction between the user interface and the data processing takes place in two different ways. On one side, the program uses some global records to define a data structure for the PageProducer. On the other side, when populating the user interface the program uses an anonymous method passed to the data module to refer to the user interface in a very flexible way. Since this is a more modern and interesting approach, I am only going to describe this second approach here.

This is the code used by the data module to fetch the information and process it (using the XMLDocument and an interface):

procedure TTweetsDataModule.GetData(const strTopic: string; processEntry: TProcessEntry); var strResult: string; feed: IXMLFeedType; I: Integer; begin // get the data from twitter strResult := IdHTTP1.Get('http://search.twitter.com/search.atom?q=' + strTopic + '&rpp=100&page=1'); XMLDocument1.LoadFromXML(strResult); XMLDocument1.Active := True; // now process the info feed := Getfeed (XMLDocument1); for I := 0 to feed.Entry.Count - 1 do begin processEntry (feed.Entry[I]); end; end;

The processEntry function called here is an anonymous method of type TProcessEntry:

type TProcessEntry = reference to procedure (iEntry: IXMLEntryType);

The main form invokes the function passing the anonymous method, which can connect the data to the user interface, keeping the two clearly separate:

procedure TTweetsForm.btnLoadClick(Sender: TObject); var

Page 51: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 50 -

item: TListItem; strTitle: string; begin ListData.Clear; TweetsDataModule.GetData (edTopic.Text, procedure (iEntry: IXMLEntryType) begin item := ListData.Items.Add; item.Caption := copy (iEntry.Id, Length ('tag:search.twitter.com,2005:') + 1, maxint); item.SubItems.Add(iEntry.Author.Name); strTitle := iEntry.Content.Text; item.SubItems.Add(strTitle); item.SubItems.Add(iEntry.Published_); item.SubItems.Add(iEntry.Link.Items[1].Href); // image item.SubItems.Add(iEntry.Link.Items[0].Href); // status item.SubItems.Add(iEntry.Author.Uri); end); end;

Using this architecture with a clear separation of the data processing part from the user interface will help us move this application to FireMonkey. In fact, I can create a very similar form and reuse most of the code. The data module and backend processing is even the same unit shared by the two projects!

FOLLOWING PIZZA TWEETS WITH FIREMONKEY Let’s now move to the FireMonkey version of the project. Unlike VCL, FireMonkey does not include a ListView control, so I’ve decided to use a StringGrid instead. This is a control you customize by adding items (that is, columns). Each column has a component name, a header, and specific settings:

object StringGrid1: TStringGrid Align = alClient ClipChildren = True StyleLookup = 'gridstyle' AlternatingRowBackground = True RowHeight = 21.0 ShowSelectedCell = False ReadOnly = True RowCount = 100 object colID: TStringColumn Width = 100.0 Height = 377.0 HitTest = False TabOrder = 1 Header = 'ID' ReadOnly = True end object colAuthor: TStringColumn Position.Point = '(100,0)' Width = 100.0 Height = 377.0 HitTest = False

Page 52: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 51 -

TabOrder = 0 Header = 'Author' end ... // and so on

After creating the user interface, we have to change the code that manages it. For example, the code used to load the elements in the interface (based on an anonymous method) now becomes:

procedure TTweetsFormFmx.btnLoadClick(Sender: TObject); var rowNo: Integer; strTitle: string; begin if edTopic.Text = '' then raise Exception.Create('Missing search element'); rowNo := 0; TweetsDataModule.GetData (edTopic.Text, procedure (iEntry: IXMLEntryType) begin // fill current row StringGrid1.Cells[colAuthor.Index, rowNo] := iEntry.Author.Name; StringGrid1.Cells[colID.Index, rowNo] := copy (iEntry.Id, Length ('tag:search.twitter.com,2005:') + 1, maxint); StringGrid1.Cells[colText.Index, rowNo] := iEntry.Content.Text; StringGrid1.Cells[colPublished.Index, rowNo] := iEntry.Published_; StringGrid1.Cells[colImage.Index, rowNo] := iEntry.Link.Items[1].Href; StringGrid1.Cells[colStatus.Index, rowNo] := iEntry.Link.Items[0].Href; StringGrid1.Cells[colUri.Index, rowNo] := iEntry.Author.Uri; // move to the next Inc (rowNo); end; end;

The user interface of the FireMonkey version of the PizzaTweets application is visible in Figure 31.

Page 53: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 52 -

Figure 31: The user interface of the FireMonkey version of the Pizza Tweets application, based on a StringGrid rather than a ListView, but with a lot of shared code

Now the advantage of this version compared to the VCL one is that we can make the program look much nicer, thanks to the features of FireMonkey, and also move it to the Mac platform.

END-PAPER ASSESSMENT Now that you have an idea of what FireMonkey is, have seen demos and quite a bit of source code, I’ll get back to the core features and reasons for using it.

First, the FireMonkey platform delivers the next incarnation of Delphi’s visual development experience, the first architecture to ever combine object-oriented programming and visual development. This is the next incarnation because rather than tying to a specific platform

Page 54: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 53 -

(like Windows), FireMonkey uses the power of modern GPUs to deliver fast native performance on multiple platforms.

Using styles, effects, animations, freely combining controls, and redefining their internal layout make FireMonkey a very nice foundation for third party controls vendors. In fact, some interesting FireMonkey controls are already starting to appear.

In this first version, the cross-platform experience is fully available for Windows and Mac OS X, with a subset of functionality available on iOS. This foundation is likely to be extended in the future to other platforms, as there is nothing inherent to it that is tied to Windows, or to a desktop PC. In fact you can already build an iOS application with rich graphics using FireMonkey today which is a clear indication of the future path.

Although I haven’t specifically focused on this issue in my demos, performance is a key factor. If you look at how smooth the 3D menu animation is even on rather old hardware, you get an idea of the power of using both the CPU and the GPU in a native way. As I explained in the introduction, at the moment there is no other library with this power. FireMonkey applications start right away, perform fast, and have no dependency on third party libraries or large frameworks to be installed on the target computer.

Of course, this paper is meant to be only an introduction to FireMonkey, as there is a lot more to learn about it. The introduction of FireMonkey is certainly going to be a revolution for Delphi, although VCL is still here to stay for time to come. But FireMonkey clearly goes beyond Delphi and offers a new application development platform for the developer community at large.

Page 55: Discover Fire Monkey Whitepaper by Marco Cantu

Discover FireMonkey, The Next Generation Business Application Platform

Embarcadero Technologies - 54 -

ABOUT THE AUTHOR Marco is the author of the best-selling Mastering Delphi series and of the recent Delphi Handbooks series he self-published. His latest works include Delphi 2010 Handbook and Delphi XE Handbook, but there is also an ebook with his Handbooks Collection (over 1,000 pages of material about recent versions of Delphi). Marco is currently working on a FireMonkey book, which will take time to complete given the complexity of this new application platform. The available books are listed at www.marcocantu.com

Marco can give onsite Delphi training classes worldwide and is available for local or remote consulting. He organizes the yearly Delphi Developer Days event with Cary Jensen, in the US and Europe.

Besides working on Delphi, Marco is available for consulting on Web architectures and the integration of Delphi projects with the web, both in terms of calling other servers and exposing them to the world.

You can read Marco's blog at blog.marcocantu.com, follow him on Twitter at twitter.com/marcocantu, and contact him on [email protected].

Embarcadero Technologies, Inc. is the leading provider of software tools that empower application developers and data management professionals to design, build, and run applications and databases more efficiently in heterogeneous IT environments. Over 90 of the Fortune 100 and an active community of more than three million users worldwide rely on Embarcadero’s award-winning products to optimize costs, streamline compliance, and accelerate development and innovation. Founded in 1993, Embarcadero is headquartered in San Francisco with offices located around the world. Embarcadero is online at www.embarcadero.com.