Categories
Android devices News Source Code

WebBroker on Android and Raspberry Pi 3

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!

Previous webinars:

Delphi and C++Builder on Raspberry Pi and SBC

Slides

Revisiting Raspberry Pi, Android and the SBC

Slides

See also: Targeting Chrome OS with Delphi via Android and Linux

Categories
News

Animated Path Graphics of Grace Hopper

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 . . . .

Grace Hopper illustration by gingercoons

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, '&#xA;', '', [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.