The plans are already underway, and you can see the current work in progress at delphiorg.github.io. I am doing what I can to preserve page URLs and find and fix broken content & episodes….
For starters I migrated from WordPress to Jekyll on GitHub pages using a slightly modified version of Prism.js for syntax highlighting. All of the content is markdown (mixed with html), so I can easily move to a new platform in the future, or use Pandoc to convert to another format.
Lady Ada Lovelace is generally considered the world’s first computer programmer. Born Augusta Ada Byron, in 1815, she was the daughter of Lord Byron, the English romantic poet. She took an interest in mathematics and her talents lead her to work with Charles Babbage, “the father of computers,” whom she met in 1833.
Babbage started work on his Difference Engine, as a means to automatically calculate and print the values of polynomial functions. While he never saw his Difference Engine completed, two were finished in modern times based on his original designs. One of which is in the Computer History Museum in Silicon Valley, where I saw it in operation.
In 1837 Babbage first described his Analytical Engine, as a general-purpose computer. In 1843, Lovelace translated a French paper that Italian mathematician Luigi Menabrea wrote about Charles Babbage’s Analytical Engine. While translating it she added thousands of words of her own notes to the paper. As an example she wrote of one such sequence—how to calculate Bernoulli numbers. This is regarded by computer historians as the first computer program.
program LovelaceBernoulli;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
function B7: extended;
(*
* Calculates what Lady Ada Lovelace labeled "B7",
* which today we would call the 8th Bernoulli number.
* Based on https://gist.github.com/sinclairtarget/ad18ac65d277e453da5f479d6ccfc20e
* More info https://twobithistory.org/2018/08/18/ada-lovelace-note-g.html
* Bernoulli Numbers: https://en.wikipedia.org/wiki/Bernoulli_number
*)
begin
// ------------------------------------------------------------------------
// Data
// ------------------------------------------------------------------------
var v1: Single := 1; // 1
var v2: Single := 2; // 2
var v3: Single := 4; // n
// ------------------------------------------------------------------------
// Working Variables
// ------------------------------------------------------------------------
var v4: Single := 0;
var v5: Single := 0;
var v6: Single := 0; // Factors in the numerator
var v7: Single := 0; // Factors in the denominator
var v8: Single := 0;
var v10: Single := 0; // Terms remaining count, basically
var v11: Single := 0; // Accumulates v6 / v7
var v12: Single := 0; // Stores most recent calculated term
var v13: Single := 0; // Accumulates the whole result
// ------------------------------------------------------------------------
// Result Variables
// ------------------------------------------------------------------------
var v21: Single := 1.0 / 6.0; // B1
var v22: Single := -1.0 / 30.0; // B3
var v23: Single := 1.0 / 42.0; // B5
var v24: Single := 0; // B7, not yet calculated
// ------------------------------------------------------------------------
// Calculation
// ------------------------------------------------------------------------
// ------- A0 -------
(* 01 *) v6 := v2 * v3; // 2n
(* 02 *) v4 := v6 - v1; // 2n - 1
(* 03 *) v5 := v6 + v1; // 2n + 1
// In Lovelace's diagram, the below appears as v5 / v4, which is incorrect.
(* 04 *) v11 := v4 / v5; // (2n - 1) / (2n + 1)
(* 05 *) v11 := v11 / v2; // (1 / 2) * ((2n - 1) / (2n + 1))
(* 06 *) v13 := v13 - v11; // -(1 / 2) * ((2n - 1) / (2n + 1))
(* 07 *) v10 := v3 - v1; // (n - 1), set counter?
// A0 = -(1 / 2) * ((2n - 1) / (2n + 1))
// ------- B1A1 -------
(* 08 *) v7 := v2 + v7; // 2 + 0, basically a MOV instruction
(* 09 *) v11 := v6 / v7; // 2n / 2
(* 10 *) v12 := v21 * v11; // B1 * (2n / 2)
// A1 = (2n / 2)
// B1A1 = B1 * (2n / 2)
// ------- A0 + B1A1 -------
(* 11 *) v13 := v12 + v13; // A0 + B1A1
(* 12 *) v10 := v10 - v1; // (n - 2)
// On the first loop this calculates B3A3 and adds it on to v13.
// On the second loop this calculates B5A5 and adds it on.
while (v10 > 0) do
begin
// ------- B3A3, B5A5 -------
while (v6 > 2 * v3 - (2 * (v3 - v10) - 2)) do
begin // First Loop:
(* 13 *) v6 := v6 - v1; // 2n - 1
(* 14 *) v7 := v1 + v7; // 2 + 1
(* 15 *) v8 := v6 / v7; // (2n - 1) / 3
(* 16 *) v11 := v8 * v11; // (2n / 2) * ((2n - 1) / 3)
// Second Loop:
// 17 v6 := v6 - v1; 2n - 2
// 18 v7 := v1 + v7; 3 + 1
// 19 v8 := v6 / v7; (2n - 2) / 4
// 20 v11 := v8 * v11; (2n / 2) * ((2n - 1) / 3) * ((2n - 2) / 4)
end;
// A better way to do this might be to use an array for all of the
// "Working Variables" and then index into it based on some calculated
// index. Lovelace might have intended v14-v20 to be used on the
// second iteration of this loop.
//
// Lovelace's program only has the version of the below line using v22
// in the multiplication.
if (v10 = 2) then
(* 21 *) v12 := v22 * v11 // B3 * A3
else
(* 21 *) v12 := v23 * v11; // B5 * A5
// B3A3 = B3 * (2n / 2) * ((2n - 1) / 3) * ((2n - 2) / 4)
// ------- A0 + B1A1 + B3A3, A0 + B1A1 + B3A3 + B5A5 -------
(* 22 *) v13 := v12 + v13; // A0 + B1A1 + B3A3 (+ B5A5)
(* 23 *) v10 := v10 - v1; // (n - 3), (n - 4)
end;
(* 24 *) v24 := v13 + v24; // Store the final result in v24
(* 25 *) v3 := v1 + v3; // Move on to the next Bernoulli number!
// This outputs a positive number, but really the answer should be
// negative. There is some hand-waving in Lovelace's notes about the
// Analytical Engine sorting out the proper sign.
Result := v24;
end;
begin
try
Writeln('Calculates what Ada Lovelace labeled "B7", which today we would call the 8th Bernoulli number.');
Writeln('--------------');
Writeln('This outputs a positive number, but really the answer should be negative.');
Writeln('There is some hand-waving in Lovelace''s notes about the Analytical Engine sorting out the proper sign.');
Writeln('==============');
Writeln(Format('A0 + B1A1 + B3A3 + B5A5: %.4f',[B7]));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Writeln('--------------');
Writeln('Press [enter] to close');
readln;
end.
While this is one way to calculate the 8th Bernoulli number, what would a modern implementation look like? Using Rudy’s Big Numbers library I created a sample application to calculate any Bernoulli number.
function Bernoulli(n: Uint64): BigRational;
begin
var a: TArray<BigRational>;
SetLength(a, n + 1);
for var m := 0 to High(a) do
begin
a[m] := BigRational.Create(1, m + 1);
for var j := m downto 1 do
begin
a[j - 1] := (a[j - 1] - a[j]) * j;
end;
end;
Result := a[0];
end;
You can install the BigNumbers library via GetIt and this sample application is included.
Over the years I’ve heard a lot of reasons or excuses people don’t use Delphi. I’ve collected the thirteen best reasons here.
1. Want to Write More Code – Delphi requires less code to accomplish the same task. If you want to write more code, don’t use Delphi. Especially helpful if writing more code gives you more sense of accomplishment, or you are paid based on lines of code written.
2. Larger Developer Teams – Who doesn’t love having lots of co-workers? If you use other tools and frameworks then you will need more developers, more developer tools, more frameworks, and more teams to support all the platforms. Makes for better office parties. Unfortunately, when you use Delphi you only need to write the app once for all the platforms, so one team and one code base for all the platforms. With Delphi, you just can’t justify hiring all those extra developers!
3. Like Fixing Bugs – All that code you had to write to implement the features on each platform? More code means more bugs! And more bugs means more job security for you and that huge team of testers. Gotta love bugs! Heck, you can even name some and keep them as pets! You know they will be around for a while.
4. More Meetings – Since each platform has its own code and own team you need more meetings to coordinate. You don’t want features to get out of sync between platforms! And then another round of meetings to coordinate bug fixes for each platform. Everyone knows meetings have the best snacks! Since Delphi lets you support all the platforms from one codebase then you can’t have all those planning meetings!
5. More Documentation – Each platform has a completely different app (despite all the meetings to keep them in sync) so now you need completely different documentation for each platform. We know how much you love writing code, so clearly you love writing end-user documentation too!
6. Larger Support Department – Each platform has its own version so you need to talk to a support tech that knows that version of the app. Who wants an Android version that behaves similar to the iOS version? Not to mention the desktop versions!
7. Longer Compile Times – If it isn’t weren’t for long compiles developers would never get a break from their desk. We all know Delphi compiles super fast, which means you have less time to slack off.
‘Are you stealing those LCDs?’ ‘Yeah, but I’m doing it while my code compiles.’
If Delphi can compile 1 million lines that quick, when will you slack off?
8. Slower Execution – If your executable runs slower the user feels safer and pretends that a lot of stuff is going on in the background. With Delphi’s native execution speed your programs are fast, so your users won’t believe it is doing anything.
9. Separated Runtime – If your program depends on an external runtime library instead of having one executable on Windows, you can blame the runtime for any bugs. All those support calls just result in telling them to update or rollback the runtime libraries. You’ll be able to convince them it is all their fault that the program doesn’t work!
10. Putting Memory to Use – Great apps should use at least a full GB of memory just like small Electron utilities do. The great thing about Electron is it includes all of the Chrome browser features like Xbox 360 controller support. Why only use a few megabytes of memory for the same simple app? The more memory the better app. Electron puts all those CPU cores to use too!
11. In Deep Love With “DLL Hell” – You love sending your customer a dozen DLLs along with your EXE and you are having so much fun to debug over the phone, which DLL is not up-to-date and makes your app fail. Closely related to #9, but worth mentioning twice!
12. Unexpected Garbage Collection Pauses – Deterministic execution is boring! What fun is it to have your program behave the same every time it runs. Delphi doesn’t have any of those unexpected garbage collection pauses to mix things up. It gives you deterministic memory management either through ref-counting, an ownership / auto-free model, or whatever level of control you want. Why control when the memory is free when you can just wait for the garbage collector?
13. Would Rather “Re-Invent the Wheel” – Delphi comes with so many useful components and libraries and has a rich 3rd party ecosystem. This means there is usually some reusable code for any task you need. That means less opportunity to create something new.
Just in case it wasn’t obvious: This is a sarcastic list of bad reasons not to use Delphi. The reality is all the excuses are just reasons to use Delphi.
Here are some of the suggestions from the community (with my commentary), followed by a few of my suggestions.
Robert Love suggested Slides.com – it is a paid web based presentation service centered around web standards. It includes built in features for making your code snippets look nice. Pro: Includes the code as text. Con: One more monthly fee (there is a free plan).
Glenn Dufke suggested pasting the code with Syntax Highlighting preserved – By default the RAD Studio/Delphi IDE doesn’t maintain this, but the GExperts IDE Plugin has a Source Code Export expert (I used to use this). I’m sure there are others (CnPack maybe?)
David Schwartz suggested just doing a screenshot from the IDE – this preserves your artistic view of how you have your IDE configured. Downside is the code can’t be easily extracted from the slides . . .
Bruce McGee suggested reveal.js – I’ve not used it yet, but it is a full web standard presentation framework, and looks promising. It uses highlight.js for the syntax highlighting, which I have used. With support for 185 languages, it has you covered. I’ll certainly be checking that one out. Thanks Bruce!
Now for my suggestions. In the past I’ve used the rich export options like Glenn suggested, colorized the text by hand, or used an intermediary like Notepad++, etc. But here are some options specifically around creating code screenshots.
Greenshot – is my current preferred desktop screenshot tool for pulling images directly from the IDE. It includes a nice editor for your screenshots too, so you can quickly annotate them, blur things out, etc.
Carbon.now.sh is a web page that takes your code and converts it into a nice image with a macOS style window. There are a few customization options. If you embed it or share it via URL then it provides both the source code and the preview. It doesn’t list Delphi as a language, but the Pascal support is close enough.
Codeimg.io is similar to Carbon, but has more configuration options. The best part is that you can use templates sized exactly for different social media platforms. A lot more customization options, including both Windows and macOS window styles. It doesn’t appear to offer a share by URL or embed option, and only does the image generation. For some reason it defaults to a JPG instead of a PNG for the image though (also supports SVG). Newer addition and still in beta.
src2img is a no-nonsense straightforward converter that turns out Source into a PNG file. Just select language (auto detects Delphi) and style. It is based on highlight.js and the source is on GitHub. Doesn’t offer a link share, just image download.
Instacode is the Instagram of the bunch, with image filters like tilt shift and 3D rotation. Directly supports Delphi language, and you can share via a URL that allows someone to access the code and remix the image. Even has wallpaper generator.
Lastly, if you have some Photoshop skills (or can follow tutorials like I do) then you can make your own. This is a combination of screenshots, with perspective warps, a few filters, background images, etc.
Did I mention CodeRage 2019 is coming soon?
How do you pretty print your source code? Which of the above is your favorite, or what did I miss?
I was a guest on X-Keys 5 Minute Friday showing off an integration between OBS Studio with the X-Keys XK-24 USB Keypad. I created a script that assigns F13 through F24 with and without the CTRL modifiers to the XK-24. You can simply assign these in the OBS hotkey settings and it will respond to those globally.
Here is the MW3(VB) script you can load into MacroWorks obs-xk-24.mw3
For some reason the F24 and CTRL+F24 didn’t work. I’m not sure if that is an OBS issue or where the cause originates. This would allow you to use your XK-24 with any software that that allows you to assign F13-F24 and recognizes global hotkeys.
10.3 Rio’s installer (I use and recommend the EXE/web over the ISO, since it is faster and more flexible) does a fantastic job of installing and setting everything up for Android development, without requiring any manual steps. Still, sometimes it is nice to be able to manually install everything, which brings me to this guide.
I’m a big believer in understanding the way the underlying systems work, and installing this way is more work, but you are able to see how everything works together. Also, this allows you to share SDKs between multiple installations, and also place the tools like ADB on your path for easy use. Not to say you can’t do all of that with the automatic install, but sometimes it is nice to get your hands dirty.
I also occasionally run into people who are having trouble getting things installed for various reasons. So this is a great way to troubleshoot installation issues.
This assumes you already have RAD Studio, Delphi, or C++Builder 10.3 Rio already installed. 10.3 Rio changed the versions of the SDK and NDK that it uses, so this guide won’t work with other versions. Also, I switched to AdoptOpenJDK instead of the traditional Oracle JDK. I’ll show you how to install that here, but if you use a different JDK that will be different for you.
What is the OpenJDK?
OpenJDK is a free and open-source implementation of the Java Platform, Standard Edition. It is the result of an effort Sun Microsystems began in 2006. The implementation is licensed under the GNU General Public License version 2 with a linking exception. It is the official reference implementation of Java SE since version 7.
There are multiple builds available, with different terms and support options. Why not just use the Java SE JDK? Oracle has changed the license on it that may require you to purchase a license to use it. For my purposes it is better save than sorry, plus the OpenJDK is a lot smaller and less annoying. I picked AdoptOpenJDK, which seems to be the most popular option, but this should mostly work the same with any build.
AdoptOpenJDK includes the JRE (Java Runtime Environment) too, so just one install. You must install it first because you can’t run the Android SDK manager without Java installed, and the IDE users the JDK for KeyTool and JarSigner.
AdoptOpenJDK Install Instructions
Download the Windows installer for OpenJDK 8 (LTS). I used the 64-bit Windows version with the HotSpot JVM, and then just run the installation. Be sure to tell it to set the JAVA_HOME environment variable.
While installing AdoptOpenJDK, have it Set JAVA_HOME environment variable.
Installing the Android SDK
When you visit the site to download the Android SDK they try to get you to download the full Android Studio, but you don’t need all of that. If you scroll to the bottom, you will see the “Command line tools only” downloads. One note, the downloads listed on the site no longer include the GUI SDK Manager. If you scroll down further, I’ll show you how you can download that and use it instead.
This isn’t an installer, so just pick a folder to unzip it into. You will just find a “tools” folder in the zip. This contains the SDK Manager to install the rest of the Android SDK. I typically unzip it into the folder:
Then use the sdkmanager command-line tool (in the tools\bin folder) to install everything you need. Notice I am installing the Android 26 Platform. This is the version you want to use with 10.3 Rio. It meets the new Target SDK requirements and still gives your Android apps maximum compatibility. This is the version 10.3 Rio is designed to work with.
The fact we are installing an older version of the SDK isn’t a big deal because we will still update it when we are done, but now we have a choice of using the command-line interface like I showed in the previous section, or using the GUI SDK Manager by running the Android.bat file in the tools folder.
Once you run the SDK manager, you want to install the latest Android SDK Tools, Android SDK Platform-tools, Android SDK Build-tools, Android API 26 SDK Platform, and the Google USB Driver. It will default to installing a lot of other things you don’t need. Feel free to deselect those. The Google USB Driver isn’t technically needed, but is nice to have.
The GUI for the Android SDK Manager
Once you’ve selected what you want installed, you can always update them via the command line with the sdkmanager utility in the tools\bin folder
sdkmanager --update
Installing the Android NDK
10.3 Rio updated the version of the Android NDK it uses to release 17b. It was the latest at the time of Rio’s development. There have been some new NDK releases since then. If you visit the Older Releases page for the Android NDK you will see 17b isn’t listed there, but the download file is still available. 17c may work, but I haven’t tested it extensively yet.
The NDK is also a zip file, so just extract it to the folder of your choosing. I’ll extract it next to my Android SDK. The root folder in the zip file is “android-ndk-r17b”
There are no further installation steps necessary. Your folders should look something like this when you are done:
The folder containing the Android SDK and NDK
I’ve expanded the directories so you can see the build tools and Android platforms also installed
Environment Variables and System Path
Last thing you need to do is set up some Environment Variables and add things to your system path. This isn’t strictly necessary, but I highly recommend it!
Make sure your JAVA_HOME is correct, and set the ANDROID_HOME environment variable.
Then add the following to your system path
%JAVA_HOME%\bin (you can replace the expanded version with this)
%JAVA_HOME%\jre\bin
%ANDROID_HOME%\tools
%ANDROID_HOME%\tools\bin
%ANDROID_HOME%\platform-tools
The first JAVA path is the JRE, the second is the JDK. Using the environment variables in the path saves environment space.
Settings Up the IDE SDK Manager
Since we’ve installed the SDK manually, we need to tell the IDE where to find it. This is really simple. Go into Tools ? Options ? Deployment ? SDK Manager (or just use the IDE search for SDK Manager) and add a new SDK entry.
If you have an existing Android entry here, you can remove it before adding a new one.We are adding a new Android platform.Provide the three paths based on where you installed them
The next stage in the wizard looks to make sure it can find everything it needs. If you didn’t install everything with the Android SDK Manager, then you may see a warning symbol next to something. If that is the case go back and double check the installation.
Be sure you select Android-26 for the API level, especially if you installed other versions too. The SDK Manager found everything it needs to continue.
And with that you are ready to develop and deploy Android apps with FireMonkey.
I covered this previously in a few webinars and presentations, but never published the source code for WebBroker on Android. To be honest I hadn’t tested it with C++Builder before, but I completely expected it to work, and it did. I also updated the tests on Emteria.OS (FKA RTAndroid) and it also works there.
The process of porting a Delphi or C++Builder WebBroker project to Android is pretty straight forward, but I’m publishing the code anyway. You create a Windows FMX WebBroker project, then copy all the code into a regular FireMonkey project. You will need to copy a few files from the RTL folder locally so you can reference them since they aren’t included in the Android package.
Web.WebReq.pas
Web.WebBroker.pas
Web.WebConst.pas
IdHTTPWebBrokerBridge.pas
IdCompilerDefines.inc
For C++Builder you also need
Web.WebReq.hpp
Web.WebBroker.hpp
Web.WebConst.hpp
IdHTTPWebBrokerBridge.hpp
Here are the links for the Delphi and C++Builder projects. They were built and tested in with 10.3.1 Rio. I also compiled some updated details on how to build the project and how to install and test on Emteria.OS.
I mention this in the slide deck, but officially WebBroker isn’t supported on Android. I tested it, and it seems to work, but if you run into an instance where it doesn’t work as expected, then you are on your own. Please don’t contact support and tell them I said it should work. Thanks!
I wanted to finish this side project during Women’s History Month to honor the Amazing Grace Hopper and her contributions to the field of Computer Science. I found this interesting SVG of Grace Hopper that wanted to figure out how to render in Delphi using the FireMonkey TPath, but it also looked like it should be animated somehow . . . .
I’ve rendered some simple SVG graphics with the TPath component before, but this one was more complicated. It has multiple colors and variable opacity. This requires multiple TPath instances to handle each variation. It was a simple matter of loading in the SVG file using an IXMLDocument, then parsing the elements, and creating a TPath for each one. For fun I included a variable sleep between each draw. Also, to make sure all the paths have the same relative size I added a couple MoveTo calls to define the client area.
var
XmlSvg: IXMLDocument;
val: String;
vals: TArray<String>;
node: IXMLNode;
path: TPath;
begin
tabControl.ActiveTab := TabItem2;
// This removes the encoded carriage returns
XmlSvg := LoadXMLData(StringReplace(memo1.Text, '
', '', [rfReplaceAll]));
if XmlSvg.DocumentElement.HasAttribute('viewBox') then
begin
val := XmlSvg.DocumentElement.Attributes['viewBox'];
vals := val.Split([' ']);
SVGLayout.Width := vals[2].ToInteger - vals[0].ToInteger;
SVGLayout.Height := vals[3].ToInteger - vals[1].ToInteger;
end;
for var idx := 0 to XmlSvg.DocumentElement.ChildNodes.Count - 1 do
begin
node := XmlSvg.DocumentElement.ChildNodes[idx];
if (node.NodeName = 'path') and (node.HasAttribute('d')) then
begin
path := TPath.Create(svgLayout);
path.Parent := svgLayout;
path.WrapMode := TPathWrapMode.Stretch;
path.Align := TAlignLayout.Contents;
path.Data.Data := node.Attributes['d'];
path.Data.MoveTo(TPointF.Zero);
path.Data.MoveTo(TPointF.Create(SVGLayout.Width, SVGLayout.Height));
if node.HasAttribute('opacity') then
path.Opacity := StrToFloat(node.Attributes['opacity']);
if node.HasAttribute('fill') and (node.Attributes['fill'] <> 'none') and (node.Attributes['fill'] <> '') then
path.Fill.Color := TAlphaColorRec.Alpha or StringToAlphaColor(node.Attributes['fill']);
end;
Sleep(Trunc(TrackBar1.Value));
svgLayout.Repaint;
Application.ProcessMessages;
end;
This is by no means a complete implementation of the SVG standard, but it is getting closer! Close enough for some simple SVG images though, and possibly a useful basis for more complicated ones.
The animations was just a matter of assigning a TFloatAnimation to each TPath that adds some random movement. I included both slight scales and rotations. I could have done both on each, but was afraid that might be too much movement.
var
dance: TFloatAnimation;
path: TPath;
I: Integer;
begin
for I := 0 to pred(SVGLayout.ChildrenCount) do
begin
if SVGLayout.Children[I] is TPath then
begin
path := SVGLayout.Children[I] as TPath;
dance := TFloatAnimation.Create(nil);
dancers.Add(dance);
dance.Parent := Path;
dance.AutoReverse := True;
dance.Loop := True;
dance.StartFromCurrent := True;
case random(4) of
0: begin
case random(2) of
0: dance.PropertyName := 'Scale.X';
1: dance.PropertyName := 'Scale.Y';
end;
case random(2) of
0: dance.StopValue := 1.01;
1: dance.StopValue := 0.99;
end;
end;
1: begin
case random(2) of
0: begin
dance.PropertyName := 'Position.X';
case random(2) of
0: dance.StopValue := Path.Position.X - random - 0.01;
1: dance.StopValue := Path.Position.X + random + 0.01;
end;
end;
1: begin
dance.PropertyName := 'Position.Y';
case random(2) of
0: dance.StopValue := Path.Position.Y - random - 0.01;
1: dance.StopValue := Path.Position.Y + random + 0.01;
end;
end;
end;
end;
2..3: begin
dance.PropertyName := 'RotationAngle';
path.RotationCenter.X := random;
path.RotationCenter.Y := random;
case random(2) of
0: dance.StopValue := random + 0.01;
1: dance.StopValue := -1 * random - 0.01;
end;
end;
end;
dance.Enabled := True;
end;
end;
And we end up with something like this . . .. (Down scaled and lower FPS)
I’m posting my code if you want to play with it some more. The source SVG is embedded in a memo instead of reading it from a file. It was written with Delphi 10.3.1 Rio.
A lot going on today for Delphi. Celebrating 24 years as being our favorite development tool, and also got the 10.3.1 Rio release! I wanted to do something fun for today, but I keep getting all wrapped up with webinars and other things, so this is a bit last minute, but still fun I think . .. .
I’ve been playing with SVG and the TPath shape component. If you are not familiar with SVG it stands for Scalable Vector Graphic and is a vector graphic format based on XML. I’ve always liked SVG, and am glad that it is finally catching on (in Oct 2018 they recommended a candidate for SVG2!) TPath on the other hand is a FireMonkey shape component that complex draws 2D shapes. Turns out the Path Data used by TPath is compatible with SVG path data.
There are a few full blown SVG components [RiverSoftAVG, BVerhue, M. Walter’s, Ekot1, and probably more…] for Delphi, but for fun I’ve been experimenting with building my own: having Delphi read the SVG XML file, and then render it with shapes, layouts, paths, etc. Not sure if it will ever get to a usable state, but I thought I would share a little TPath fun with you.
Create a new FireMonkey application and copy and paste this component onto your form.
Or if you would rather just paste the path data into a new TPath component of your own you can do that too (just make sure it is square for the right aspect ratio and set the Fill color):
M 499.996 185.685 C 500.673 282.217 411.317 315.926 353.636 356.897 C 300.877 394.36 255.711 447.001 250.27 468.359 C 243.913 446.564 203.354 395.367 146.37 357.94 C 87.596 319.354 -0.667 283.269 0.004 186.738 C 1.214 10.975 185.692 -37.617 250.41 113.819 C 312.154 -31.581 498.776 9.49 499.996 185.685 Z M 211.574 374.131 C 224.398 374.131 239.97 375.963 257.374 379.627 L 266.533 363.139 L 256.458 341.155 C 245.466 339.323 235.39 338.407 227.146 338.407 C 204.247 338.407 200.583 345.735 200.583 345.735 L 186.843 377.795 C 191.423 375.963 199.667 374.131 211.574 374.131 Z M 206.994 345.735 C 218.902 342.071 231.014 341.448 237.222 343.903 C 229.894 341.155 210.658 347.567 210.658 347.567 L 196.919 366.803 Z M 175.495 317.519 L 140.152 325.868 C 142.016 330.859 143.5 334.57 144.604 337
C 145.709 339.43 147.471 342.862 149.892 347.297 L 182.731 329.764 Z M 169.712 299.497 L 132.081 291.637 C 132.591 296.206 133.055 299.638 133.472 301.934 C 133.89 304.23 134.725 307.941 135.977 313.066 L 173.547 312.76 C 172.578 310.076 171.836 308.045 171.321 306.665 C 170.806 305.286 170.27 302.897 169.712 299.497 Z M 167.703 271.54 L 132.916 249.893 C 132.014 256.899 131.457 262.094 131.246 265.477 C 131.035 268.86 131.035 273.684 131.246 279.949 L 168.26 292.75 C 167.792 288.175 167.514 284.743 167.425 282.453 C 167.336 280.164 167.428 276.526 167.703 271.54 Z M 173.547 247.666 L 145.161 209.539 C 142.577 215.412 140.722 219.957 139.595 223.176
C 138.468 226.394 137.077 231.126 135.421 237.369 L 168.538 266.59 C 169.442 261.919 170.184 258.486 170.764 256.293 C 171.345 254.1 172.273 251.225 173.547 247.666 Z M 190.245 221.506 L 177.444 164.455 C 170.974 171.095 166.243 176.29 163.25 180.04 C 160.257 183.789 156.547 189.17 152.118 196.181 L 175.495 243.213 C 178.402 237.882 180.628 234.079 182.175 231.803 C 183.721 229.528 186.411 226.095 190.245 221.506 Z M 222.249 199.521 L 234.495 128.833 C 222.951 133.828 214.324 137.909 208.613 141.078 C 202.902 144.247 196.316 148.607 188.854 154.158 L 194.141 217.332 C 200.474 212.197 205.298 208.579 208.613 206.478 C 211.928 204.377 216.474 202.058 222.249 199.521 Z M 261.211 193.398 L 299.616 122.154 C 288.313 121.306 279.5 121.12 273.178 121.597 C 266.856 122.074 258.414 123.28 247.853 125.215 L 228.65 196.738 C 236.473 194.908 242.317 193.795 246.183 193.398 C 250.049 193.002 255.058 193.002 261.211 193.398 Z M 299.509 205.589 L 368.913 147.201 C 360.935 141.82 352.771 137.367 344.422 133.842
C 336.073 130.317 327.446 127.441 318.541 125.215 L 270.384 194.923 C 274.525 195.545 279.81 197.003 286.24 199.297 Z M 312.333 375.963 C 311.417 372.299 304.089 340.239 275.693 320.088 C 274.777 319.172 261.038 308.18 254.626 299.936 L 244.55 301.768 L 288.517 397.03 C 294.013 395.198 311.417 386.954 312.333 375.963 Z M 335.232 274.288 L 326.072 217.497 L 229.894 284.364 L 232.642 294.44 Z M 239.138 298.104 L 229.978 299.936 L 226.314 282.532 L 316.081 221.161 C 299.593 205.59 277.609 195.513 256.542 195.513 C 209.826 195.513 171.355 233.985 171.355 280.7 C 171.355 304.516 181.431 327.415 198.835 342.987 C 200.667 340.239 206.163 333.827 229.062 333.827 C 237.306 333.827 246.466 334.743 257.458 336.575 Z M 196.003 326.499 C 150.203 247.725 227.146 210.169 237.222 206.505 C 228.062 210.169 155.699 254.137 202.415 323.751 C 199.667 325.583 196.003 327.415 196.003 326.499 Z
If you are curious what the whole SVG file looks like, here it is:
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<path id="Delphi" d="M 499.996 185.685 C 500.673 282.217 411.317 315.926 353.636 356.897 C 300.877 394.36 255.711 447.001 250.27 468.359 C 243.913 446.564 203.354 395.367 146.37 357.94 C 87.596 319.354 -0.667 283.269 0.004 186.738 C 1.214 10.975 185.692 -37.617 250.41 113.819 C 312.154 -31.581 498.776 9.49 499.996 185.685 Z M 211.574 374.131 C 224.398 374.131 239.97 375.963 257.374 379.627 L 266.533 363.139 L 256.458 341.155 C 245.466 339.323 235.39 338.407 227.146 338.407 C 204.247 338.407 200.583 345.735 200.583 345.735 L 186.843 377.795 C 191.423 375.963 199.667 374.131 211.574 374.131 Z M 206.994 345.735 C 218.902 342.071 231.014 341.448 237.222 343.903 C 229.894 341.155 210.658 347.567 210.658 347.567 L 196.919 366.803
Z M 175.495 317.519 L 140.152 325.868 C 142.016 330.859 143.5 334.57 144.604 337 C 145.709 339.43 147.471 342.862 149.892 347.297 L 182.731 329.764 Z M 169.712 299.497 L 132.081 291.637 C 132.591 296.206 133.055 299.638 133.472 301.934 C 133.89 304.23 134.725 307.941 135.977 313.066 L 173.547 312.76 C 172.578 310.076 171.836 308.045 171.321 306.665 C 170.806 305.286 170.27 302.897 169.712 299.497 Z M 167.703 271.54 L 132.916 249.893 C 132.014 256.899 131.457 262.094 131.246 265.477 C 131.035 268.86 131.035 273.684 131.246 279.949 L 168.26 292.75 C 167.792 288.175 167.514 284.743 167.425 282.453 C 167.336 280.164 167.428 276.526 167.703 271.54 Z M 173.547 247.666 L 145.161 209.539 C 142.577 215.412 140.722 219.957 139.595 223.176 C 138.468 226.394 137.077 231.126 135.421 237.369 L 168.538 266.59
C 169.442 261.919 170.184 258.486 170.764 256.293 C 171.345 254.1 172.273 251.225 173.547 247.666 Z M 190.245 221.506 L 177.444 164.455 C 170.974 171.095 166.243 176.29 163.25 180.04 C 160.257 183.789 156.547 189.17 152.118 196.181 L 175.495 243.213 C 178.402 237.882 180.628 234.079 182.175 231.803 C 183.721 229.528 186.411 226.095 190.245 221.506 Z M 222.249 199.521 L 234.495 128.833 C 222.951 133.828 214.324 137.909 208.613 141.078 C 202.902 144.247 196.316 148.607 188.854 154.158 L 194.141 217.332 C 200.474 212.197 205.298 208.579 208.613 206.478 C 211.928 204.377 216.474 202.058 222.249 199.521 Z M 261.211 193.398 L 299.616 122.154 C 288.313 121.306 279.5 121.12 273.178 121.597 C 266.856 122.074 258.414 123.28 247.853 125.215 L 228.65 196.738 C 236.473 194.908 242.317 193.795 246.183 193.398 C 250.049 193.002 255.058 193.002 261.211 193.398 Z M 299.509 205.589 L 368.913 147.201 C 360.935 141.82 352.771 137.367 344.422 133.842
C 336.073 130.317 327.446 127.441 318.541 125.215 L 270.384 194.923 C 274.525 195.545 279.81 197.003 286.24 199.297 Z M 312.333 375.963 C 311.417 372.299 304.089 340.239 275.693 320.088 C 274.777 319.172 261.038 308.18 254.626 299.936 L 244.55 301.768 L 288.517 397.03 C 294.013 395.198 311.417 386.954 312.333 375.963 Z M 335.232 274.288 L 326.072 217.497 L 229.894 284.364 L 232.642 294.44 Z M 239.138 298.104 L 229.978 299.936 L 226.314 282.532 L 316.081 221.161 C 299.593 205.59 277.609 195.513 256.542 195.513 C 209.826 195.513 171.355 233.985 171.355 280.7 C 171.355 304.516 181.431 327.415 198.835 342.987 C 200.667 340.239 206.163 333.827 229.062 333.827 C 237.306 333.827 246.466 334.743 257.458 336.575 Z M 196.003 326.499 C 150.203 247.725 227.146 210.169 237.222 206.505 C 228.062 210.169 155.699 254.137 202.415 323.751 C 199.667 325.583 196.003 327.415 196.003 326.499 Z" fill="#d40000"/>
</svg>
And for those of you who are impatient, here is the output:
Rendered in Delphi with a TPath component (The strokes default to black, but you can tweak that)
And as an SVG
And since it is a vector graphic it will look great at any resolution, as long as you maintain a 1:1 aspect ratio.
What fun Delphi side projects are you working on? What did you do to celebrate the birthday of your favorite programming language?
Today, I have a webinar on Getting the Most out of Android with 10.3 Rio. I want it to be a bit of a State of Android development today, as well as a What’s New in 10.3 Rio for Android. During CodeRage 2018 presented on what’s new in 10.3 Rio around Android. That session evolved into this webinar.
Here is the Q&A log. I’ve gone back and typed answers to all the questions and included links too when possible. I may have edited some questions for length or clarity. The recording of the Q&A failed, and despite trying to recover it I wasn’t able to.
Question: what about Samsung Tizen os mobile? I think it’s different than Android OS
Answer:
When I worked for a large PC manufacturer, it was common for companies to tell Intel they were looking at AMD CPUs as a bargaining technique
Samsung mostly uses Tizen as a way to tell Google that they have options aren’t too attached to Android
Abandoning Android compatibility and ecosystem is dangerous
Question: and what about Android Intel processors or Android emulator with Intel Atom (x86)
Answer:
Intel’s Atom processors made a short appearance in Android devices
They were x86 instead of ARM base
Android 4.4 KitKat included libHoudini to provide ARM compatibility
ARM compatibility was required because of widespread native NDK apps
Most games include native NDK parts
Discontinued for Android in 2016
Question: 8.1 Oreo not yet available for S8+
Answer: That is unfortunate, I thought it was. I recently read that Android 9.0 Pie is coming.
Question: In case I need an external Android library (jar file) included in my project, what should I do?
Answer: Check out the DocWiki for information. But you can add the JAR file in the Project Manager under Targets -> Android -> Libraries and then use Java2OP to create a JNI Bridge file. There is good information in the DocWiki.
Question: Will there be the same webinar for iOS?
Answer: Maybe. I’m not as familiar with iOS, but I’ll see what I can do.
Question: Just a Note that Huawei also has a Dex equivalent and it seems to work better than Samsung’s. Please don’t ignore that
Answer: Very cool! It looks like it called EMUI Desktop on their HUAWEI Mate 10
Question: I am trying to use Drag and Drop to re-sequence TListView items and cannot find any relevant examples. (only things moving panels etc). how would I go about this?
Answer: I’ve not tried, but I’ve seen it done. I would treat the ListView items as individual items like panels and then drag those. On drop just look at where it as in the list and change the index.
Question: LivePreview are available somehow for Delphi CE?
Answer: Yes, just build it and install it. You can find the source here
Question: Are there examples of how to make accepting permissions and explain why needed?
Answer: In the DocWiki and I covered it in the webinar.
Question: Receiving “Can’t open socket: Permission denied. Exiting” message when trying to debug an Android app. Running Android 8.0. This has been a problem since 10.2.
Answer: I just tested this with Rio and a Note 9 running Oreo 8.1 and it worked fine. There was a bug in Android 8.0 that impacted all debuggers. You can find more information on Marco’s blog post.
Question: Why does Delphi take so long, literally 5+ minutes, to recognize an Android device connected, via USB, to my laptop? Windows recognizes the device immediately and I’m able to browse the device within Windows file explorer. Clicking the refresh devices button has no effect. Is there a way to speed up this device recognition process?
Answer: Odd. I’ve not seen that. If you run ADB DEVICES from the command line does it recognize it? If not then that would be an issue with the Android Debug Bridge (ADB) so could be related to your device or the ADB USB driver. The single physical device has multiple devices that Windows recognizes. One is the MTP device for transferring files, the other is the ADB device for debugging. So just because windows recognizes the MTP device doesn’t mean it has recognized the ADB device yet. What device is it?
Question: Re: Delay recognizing device: Device is a Samsung Galaxy S8+. Also tried an HTC One M7 with the same result.
Answer: Did you try ADB DEVICES from the command line? It could be a Windows issue.
Question: Re: Open Socket error: Android version 8.0. Device Samsung Galaxy S8+. Running Delphi Rio 10.3 So there’s no workaround? Given the current route that Android updates arrive at devices: Google -> Manufacturer -> Telcom -> Device means that I’m stuck with no debugging for potentially years … already been ~6 months? Debugging is the reason I’ve invested in Delphi.
Answer: That was a bug in 8.0 Oreo that was fixed in Android 8.1 – it wasn’t specific to Delphi. Unfortunately, we don’t have any control over the Android OS or what Samsung installs on their devices. Wish we did.
Question: What’s the best way to end an Android app?
Answer: Best practice on Android is that you don’t close your app, but let the OS manage that. If you need to though, then just call Close on your main form like you would on another platform. You could also try Application.Terminate and Halt.
Question: Just want to say that this has been an excellent seminar. Thank you for putting it on.
Answer: My pleasure. Glad it is of value.
Question: what are the sound capabilities in RAD Studio for Android?
Answer: You can do quite a bit. Anything that Android supports (which is a lot). There is a media player component that comes with FireMonkey. Take a look at the 4 sample games in GetIt. They have music and sound effects if I recall correctly. The great thing about using FireMonkey is you can get the productivity of all the FireMonkey components, libraries, etc. and then when you need to you can reach down and access the Android APIs just like developers who don’t use FireMonkey.
Question: Wouldn’t it nice to have a component for permissions?
Answer: The PermisionService makes it really easy, but a component could be useful too I suppose.
Question: Where are we with 64 bit for Android?
Answer: R&D is working on it and it is on the Roadmap for later 2019.
Question: Give them the coming end of GCM, any plans for built-in FCM components?
Answer: Good question. I’ll need to look into that. I know there are some free 3rd party libraries that do that.
Question: Hello. where find more info about splash screen? It not clear how to control it.
Answer: Check out the DocWiki on application properties. There are another of other options too here you can make a splash screen form. Marco has a blog post from a while ago on the subject too.
Question: I can’t find LivePreview App on Google Play Store? Does it still exist?
Answer: Not currently, but the source ships with the IDE and you can build it and install it yourself. You can find the source here
Question: is possible to active and android Delphi generated app on both and remain on background sending GPS updates? any sample?
Answer: No samples, but I believe people have done it. You would need to be concerned about the battery though. You might need to go directly to the Android GPS API. I would suggest researching Android services on the Android developer site. There are a lot of rules about them.
Question: Hello, I’m wondering why for demos all presenters use a mac? Is better have Delphi on a Mac laptop?
Answer: I prefer Windows, and most developers I know do too, but Apple requires you to have a Mac if you want to build for iOS, and since I need to demo for iOS too then it makes sense to have just one computer.
Question: Ok. It will be great a webinar about to setup Delphi on Mac !!!
Question: What about GUI test automation for mobile Delphi projects? Is there finally something available for that?
Answer: I’m not aware of anything, I know Ranorex has Delphi VCL and Android GUI Test automation, but it doesn’t look like that do Delphi on Android. You might be able to leverage the FireMonkey Accessibly Pack for something
Question:
Does the HTTP client library cover all SSL related topics or is there a need for “raw” TCP SSL sockets? If yes, the HTTP client might not be of help.
Although Android still supports SSL (Indy libraries), what about the support for the Google libraries (boring SSL).
Answer: Check out the new HTTP Client library that was introduced in XE8 – it uses the platform libraries, but don’t know if it supports Google’s Boring SSL specifically
Question: Does Fire Monkey support right to left languages like Arabic and Hebrew?
Answer: Take a look at FMX RTL. Also, if a 3rd party can do it, then you can do it yourself too. But using their library will certainly make it easier.
Question: Huawei is pronounced “hwah way” 🙂
Answer: Thanks! I tried to research it, but I am not good at pronunciations.
Question: Are improvements in FMX listed. For example, when saving a TBitmap by SaveToFile, it did not pop up in the media on Android in my previous version. I had to add this programmatically.
Answer: I believe it has to do with where you save it and what file format. Save it as a JPEG or PNG and try saving it in a shared location like TPath.GetSharedPicturesPath.
Question: No question, just a hint: someone asked for Ranorex and Android. There is documentation on ranorex.com
Answer: Cool
Question: Google just announced a few days ago “Starting August 1, 2019: All new apps and app updates that include native code are required to provide 64-bit versions in addition to 32-bit versions when publishing to Google Play.” Looks like our apps will be orphaned later this year without a 64-bit compiler – what is the ETA for a 64-bit android compiler?
Answer: The Roadmap has 10.4.x with 64-bit Android planned for “mid-2019”
Question: When will we see more common UI features as components (ie. not having to do things manually), such as slide menus, for example.
Answer: Like the TMultiView? It is a great common UI component that was introduced in XE7
Question: Can the location sensor be used in an Android service now?
Answer: I personally haven’t tested it . . . You may need to research the Android platform limitations on using location services in the background because of battery consumption issues.
Question: how can we handle the android permission requests?
Answer: It is covered in the DocWiki and here is a sample in the location samples folder
Question: Did I understand correctly that there is a C++ Builder community edition accessible and free for any non-commercial use? (i.e., creating apps for personal use and for open-source distributed apps?)
Answer: Yes, correct there is free C++Builder Community Edition
Question: Doesn’t RAD Studio (or C++ Builder) have its own emulator to “test” apps on *all* platforms in a more-or-less automatic way? (assuming that the emulation is faithful enough)
Answer: We used to offer a bundle deal with MacInCloud but it didn’t get enough use to justify continue it since most people use devices. You can use the Android emulator but it isn’t great, and there are services that let you test on devices in the cloud. Samsung offers one too specifically for their devices. I’ve also heard some people have good luck with using Bluestacks, but I haven’t tried it. There are a lot of options.
Question: Speaking of how iOS is so different and has such different nuances compared to Android…
Answer: There is a lot you can do with a complete multi-platform approach, but then there are specifics to each platform you can take advantage of. For example, your desktop has a larger screen, and more input and output options. A pure multi-device approach does a lot and makes you really productive, but then the great thing about Delphi, C++Builder, & FireMonkey is you can also take advantage of platform-specific features and APIs. Kind of a best of both worlds approach!
Question: Thanks!
Answer: welcome!
Question: but there is a lot of devices that still running 8.0! Even Samsung …
Answer: Yes, it is an unfortunate bug in Android 8.0. Samsung says they have an update coming, and I hear the beta is already available. Have you tried that?
Question: What about 64-bit on Android, iOS, and macOS?
Answer: iOS 64-bit has been available for a while, bot macOS (10.3.x) and Android 64-bit (10.4.x) are on the roadmap for release this year.
Question: what is the best way for FireMonkey mobile app to work with DB (on a server). REST or FireDAC? Or something else?
Answer:
The best way depends on your goals and the scenario.
I would recommend starting with RAD Server (EMS) using FireDAC to connect to the server database and then connect to RAD Server from your mobile app.
You could also use DataSnap in the same situation (RAD Server is more of a turnkey, while DataSnap lets you build it from scratch so more flexible).
If you don’t control the server then if the server is exposing the data over REST then you can use the REST Client libraries or the BAAS libraries
Although if it is on Azure or Amazon Cloud then use the cloud libraries
You could also use DevArt’s UniDAC to connect directly to some databases from the mobile app
Question: Hello, what is the best way to show forms and destroy it for android application?
Answer: You can show and destroy forms just like you would on other platforms, or you might consider using frames on a Tab Control. Also, take a look at TFrameStand which is available in the GetIt package manager
Question: Is C++Builder Community Edition available for macOS?
Answer: Yes, it can target macOS. The same features as C++Builder Professional
Question: Is the size of the executable file for Android, prepared in FireMonkey still a problem?
Answer: It never was a problem. A “hello world” app in FireMonkey is larger than an equivalent app in Java because FireMonkey is including a lot of other additional libraries and features for building more complicated apps. There is a lot you can do to make a FireMonkey app smaller, but you give up functionality. If you look at real apps you will see that a Java based app and a FireMonky based app are much closer to the same size.
I pulled a couple of graphics from my presentation that I thought were interesting and that you are free to share. (Select an image for the larger version.)