Thursday, March 13, 2025

Delphi FMX Air.Style Missing 'scrollboxstyle' Definition

I've been upgrading my flagship software product Zilch, from Delphi 5 VCL to Delphi 11 FMX. I'm finally in the report development phase. I'm using the FMX version of FastReports.

Things have been going along quite well, other than the typical stumbling around, which happens when learning the ins and outs of a new component suite (FastReports). 

Back in May 2024, I decided to implement a dark theme after watching Ian Barker's presentation called "The fundamental secrets of good UI design". https://www.youtube.com/live/TL2YVio_eTo

During this presentation Barker pleads with the audience to include a dark theme option because it makes life much easier for people like him. Those who suffer with severe cataracts. 

I am very meticulous about my work. Borderline obsessive. After spending nearly 4 weeks creating, tweaking, previewing, re-tweaking a report I finally decided to see what it looks like in dark mode. That's when I got hit with an access violation. 

My first reaction was WTF! 😡 


FMX.StdCtrls

I spent 3 months or more back in May 2024 testing and trying several different FMX styles. I finally settled on the Air.Style after making several customizations. And now this happens. Just when I thought I was getting close to wrapping up this project. WTF! 😡

Inside my application I'm using the StyleManager.  I call:

TStyleManager.SetStyleFromFile( <FullFilePath> )

<FullFilePath> is the full file path of the modified version of Air.Style I'm using inside my program. I remember trying Dark.Style early on but I didn't like the brownish-copper glow effect so I opted for the Air.Style.

I quickly tried setting the <FullFilePath> to Dark.Style and tested it again, IT WORKED! 😎

Okay, so there is something different between Air.Style and Dark.Style. I searched both .STYLE files looking for "TScrollBar"

It turns out that Air.Style is missing the definition for StyleName = 'scrollboxstyle'.

I copied the complete 'scrollboxstyle' definition from Dark.Style and pasted it inside Air.Style and IT WORKED!

Payoff Savings Report - Air.Style

I'm glad this was a quick fix. Here is the complete 'scrollboxstyle' definition for anyone that would like to modify the Air.Style so it works with FastReports. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
object TLayout
  StyleName = 'scrollboxstyle'
  DesignVisible = False
  Height = 131.000000000000000000
  Position.X = 254.000000000000000000
  Position.Y = 435.000000000000000000
  Width = 334.000000000000000000
  object TLayout
    StyleName = 'background'
    Align = Contents
    Locked = True
    Height = 131.000000000000000000
    Width = 334.000000000000000000
    object TLayout
      StyleName = 'content'
      Align = Client
      Height = 115.000000000000000000
      Width = 318.000000000000000000
    end
    object TScrollBar
      StyleName = 'vscrollbar'
      Align = Right
      Height = 115.000000000000000000
      Orientation = Vertical
      Position.X = 318.000000000000000000
      Width = 16.000000000000000000
    end
    object TScrollBar
      StyleName = 'hscrollbar'
      Align = Bottom
      Height = 16.000000000000000000
      Orientation = Horizontal
      Position.Y = 115.000000000000000000
      Width = 334.000000000000000000
    end
    object TSmallScrollBar
      StyleName = 'vsmallscrollbar'
      Align = Right
      Height = 8.000000000000000000
      Orientation = Vertical
      Margins.Left = 2.000000000000000000
      Position.X = 99.000000000000000000
      Position.Y = 2.000000000000000000
      Visible = False
      Width = 8.000000000000000000
    end
    object TSmallScrollBar
      StyleName = 'hsmallscrollbar'
      Align = Bottom
      Height = 8.000000000000000000
      Orientation = Horizontal
      Margins.Top = 2.000000000000000000
      Position.X = 2.000000000000000000
      Position.Y = 113.000000000000000000
      Visible = False
      Width = 150.000000000000000000
    end
    object TLayout
      Align = Contents
      Height = 131.000000000000000000
      Width = 334.000000000000000000
      object TLayout
        Align = Bottom
        Height = 20.000000000000000000
        Position.Y = 111.000000000000000000
        Width = 334.000000000000000000
        object TSizeGrip
          StyleName = 'sizegrip'
          Align = Right
          Locked = True
          Height = 20.000000000000000000
          Position.X = 314.000000000000000000
          Width = 20.000000000000000000
        end
      end
    end
  end
end


Update: March 16, 2025

I'll have to give the new Delph 12.3 command-line style converter tool (vsf2fm.exe) a try. Hat Tip to Ray Konopka for pointing me in this direction.


I just installed Delphi 12.3 and used the vsf2fm.exe command-line tool and converted the Carbon.vsf to Carbon.style and it works perfectly.


Update: March 18, 2025

Just tried targeting macOS and the Carbon.style looks fantastic.

Enjoy!
Semper Fi
Gunny Mike
https://zilchworks.com



Sunday, February 16, 2025

Delphi Tip of the Day: FMX FastReport Text Object (TfrxMemoView)

I've been playing around with FastReport in FMX. To be honest, I've been struggling a bit. So, today I decided to go back to square one and work through the FMX documentation on the FastReport website. https://www.fast-report.com/public_download/docs/FRVCL/online/en/index.html

"The "Text" object... No Problem.
HTML-tags in the "Text" object... Doesn't work as advertised.

The "Text" object (TfrxViewMemo) is extremely powerful. It accepts simple HTML tags that lets you modify a single text field in some really cool ways. It's kind of like a mini "Rich Text" object. 

Here is a what a working example is supposed to look like:



That is one text field with multiple effects applied to separate sections:
  • Bold
  • Italic
  • Bold and Italic
  • Superscript
  • Subscript
  • Color
I ran into an issue when I followed the example to create the "Orange" text. It didn't work. The Original example from the FastReports did not turn the text orange.


Using <font color="#FF8030"> did not display the text in orange. The text between the opening and closing font tags did not display at all. Seeing that the "red" font tag worked, I tried using the color name "orange". And it worked.


I then tried using the Alpha Color of  #FFFF8030 and it also worked.


I'm glad I was able to make the FastReport example work. The text object is very powerful. I experimented with several different Delphi Color name constants and they also worked. I did run into an issue with some of the obsolete color name constants, such as MoneyGreen. The FastReport designer did not recognize "MoneyGreen" as a valid integer. It did however take the MoneyGreen HEX equivalent of #FFC0DCC0.

I decided to create a the following cheat sheet of all the font color names that FastReport text object will recognize.

Name Color HEX Code

Aliceblue

Aliceblue

#FFF0F8FF

Antiquewhite

Antiquewhite

#FFFAEBD7

Aqua

Aqua

#FF00FFFF

Aquamarine

Aquamarine

#FF7FFFD4

Azure

Azure

#FFF0FFFF

Beige

Beige

#FFF5F5DC

Bisque

Bisque

#FFFFE4C4

Black

Black

#FF000000

Blanchedalmond

Blanchedalmond

#FFFFEBCD

Blue

Blue

#FF0000FF

Blueviolet

Blueviolet

#FF8A2BE2

Brown

Brown

#FFA52A2A

Burlywood

Burlywood

#FFDEB887

Cadetblue

Cadetblue

#FF5F9EA0

Chartreuse

Chartreuse

#FF7FFF00

Chocolate

Chocolate

#FFD2691E

Coral

Coral

#FFFF7F50

Cornflowerblue

Cornflowerblue

#FF6495ED

Cornsilk

Cornsilk

#FFFFF8DC

Crimson

Crimson

#FFDC143C

Cyan

Cyan

#FF00FFFF

Darkblue

Darkblue

#FF00008B

Darkcyan

Darkcyan

#FF008B8B

Darkgoldenrod

Darkgoldenrod

#FFB8860B

Darkgray

Darkgray

#FFA9A9A9

Darkgreen

Darkgreen

#FF006400

Darkgrey

Darkgrey

#FFA9A9A9

Darkkhaki

Darkkhaki

#FFBDB76B

Darkmagenta

Darkmagenta

#FF8B008B

Darkolivegreen

Darkolivegreen

#FF556B2F

Darkorange

Darkorange

#FFFF8C00

Darkorchid

Darkorchid

#FF9932CC

Darkred

Darkred

#FF8B0000

Darksalmon

Darksalmon

#FFE9967A

Darkseagreen

Darkseagreen

#FF8FBC8F

Darkslateblue

Darkslateblue

#FF483D8B

Darkslategray

Darkslategray

#FF2F4F4F

Darkslategrey

Darkslategrey

#FF2F4F4F

Darkturquoise

Darkturquoise

#FF00CED1

Darkviolet

Darkviolet

#FF9400D3

Deeppink

Deeppink

#FFFF1493

Deepskyblue

Deepskyblue

#FF00BFFF

Dimgray

Dimgray

#FF696969

Dimgrey

Dimgrey

#FF696969

Dodgerblue

Dodgerblue

#FF1E90FF

Firebrick

Firebrick

#FFB22222

Floralwhite

Floralwhite

#FFFFFAF0

Forestgreen

Forestgreen

#FF228B22

Fuchsia

Fuchsia

#FFFF00FF

Gainsboro

Gainsboro

#FFDCDCDC

Ghostwhite

Ghostwhite

#FFF8F8FF

Gold

Gold

#FFFFD700

Goldenrod

Goldenrod

#FFDAA520

Gray

Gray

#FF808080

Green

Green

#FF008000

Greenyellow

Greenyellow

#FFADFF2F

Grey

Grey

#FF808080

Honeydew

Honeydew

#FFF0FFF0

Hotpink

Hotpink

#FFFF69B4

Indianred

Indianred

#FFCD5C5C

Indigo

Indigo

#FF4B0082

Ivory

Ivory

#FFFFFFF0

Khaki

Khaki

#FFF0E68C

Lavender

Lavender

#FFE6E6FA

Lavenderblush

Lavenderblush

#FFFFF0F5

Lawngreen

Lawngreen

#FF7CFC00

Lemonchiffon

Lemonchiffon

#FFFFFACD

Lightblue

Lightblue

#FFADD8E6

Lightcoral

Lightcoral

#FFF08080

Lightcyan

Lightcyan

#FFE0FFFF

Lightgoldenrodyellow

Lightgoldenrodyellow

#FFFAFAD2

Lightgray

Lightgray

#FFD3D3D3

Lightgreen

Lightgreen

#FF90EE90

Lightgrey

Lightgrey

#FFD3D3D3

Lightpink

Lightpink

#FFFFB6C1

Lightsalmon

Lightsalmon

#FFFFA07A

Lightseagreen

Lightseagreen

#FF20B2AA

Lightskyblue

Lightskyblue

#FF87CEFA

Lightslategray

Lightslategray

#FF778899

Lightslategrey

Lightslategrey

#FF778899

Lightsteelblue

Lightsteelblue

#FFB0C4DE

Lightyellow

Lightyellow

#FFFFFFE0

Lime

Lime

#FF00FF00

Limegreen

Limegreen

#FF32CD32

Linen

Linen

#FFFAF0E6

Magenta

Magenta

#FFFF00FF

Maroon

Maroon

#FF800000

Mediumaquamarine

Mediumaquamarine

#FF66CDAA

Mediumblue

Mediumblue

#FF0000CD

Mediumorchid

Mediumorchid

#FFBA55D3

Mediumpurple

Mediumpurple

#FF9370DB

Mediumseagreen

Mediumseagreen

#FF3CB371

Mediumslateblue

Mediumslateblue

#FF7B68EE

Mediumspringgreen

Mediumspringgreen

#FF00FA9A

Mediumturquoise

Mediumturquoise

#FF48D1CC

Mediumvioletred

Mediumvioletred

#FFC71585

Midnightblue

Midnightblue

#FF191970

Mintcream

Mintcream

#FFF5FFFA

Mistyrose

Mistyrose

#FFFFE4E1

Moccasin

Moccasin

#FFFFE4B5

Navajowhite

Navajowhite

#FFFFDEAD

Navy

Navy

#FF000080

Oldlace

Oldlace

#FFFDF5E6

Olive

Olive

#FF808000

Olivedrab

Olivedrab

#FF6B8E23

Orange

Orange

#FFFFA500

Orangered

Orangered

#FFFF4500

Orchid

Orchid

#FFDA70D6

Palegoldenrod

Palegoldenrod

#FFEEE8AA

Palegreen

Palegreen

#FF98FB98

Paleturquoise

Paleturquoise

#FFAFEEEE

Palevioletred

Palevioletred

#FFDB7093

Papayawhip

Papayawhip

#FFFFEFD5

Peachpuff

Peachpuff

#FFFFDAB9

Peru

Peru

#FFCD853F

Pink

Pink

#FFFFC0CB

Plum

Plum

#FFDDA0DD

Powderblue

Powderblue

#FFB0E0E6

Purple

Purple

#FF800080

Red

Red

#FFFF0000

Rosybrown

Rosybrown

#FFBC8F8F

Royalblue

Royalblue

#FF4169E1

Saddlebrown

Saddlebrown

#FF8B4513

Salmon

Salmon

#FFFA8072

Sandybrown

Sandybrown

#FFF4A460

Seagreen

Seagreen

#FF2E8B57

Seashell

Seashell

#FFFFF5EE

Sienna

Sienna

#FFA0522D

Silver

Silver

#FFC0C0C0

Skyblue

Skyblue

#FF87CEEB

Slateblue

Slateblue

#FF6A5ACD

Slategray

Slategray

#FF708090

Slategrey

Slategrey

#FF708090

Snow

Snow

#FFFFFAFA

Springgreen

Springgreen

#FF00FF7F

Steelblue

Steelblue

#FF4682B4

Tan

Tan

#FFD2B48C

Teal

Teal

#FF008080

Thistle

Thistle

#FFD8BFD8

Tomato

Tomato

#FFFF6347

Turquoise

Turquoise

#FF40E0D0

Violet

Violet

#FFEE82EE

Wheat

Wheat

#FFF5DEB3

White

White

#FFFFFFFF

Whitesmoke

Whitesmoke

#FFF5F5F5

Yellow

Yellow

#FFFFFF00

Yellowgreen

Yellowgreen

#FF9ACD32

Osolete Color Names Use HEX Code

LtGray

LtGray

#FFC0C0C0

MedGray

MedGray

#FFA0A0A0

DkGray

DkGray

#FF808080

MoneyGreen

MoneyGreen

#FFC0DCC0

LegacySkyBlue

LegacySkyBlue

#FFF0CAA6

Cream

Cream

#FFF0FBFF



Enjoy!
Semper Fi
Gunny Mike

Thursday, January 2, 2025

Tip of the Day - Everyday is an Etch-A-Sketch

Sometimes all you need is a little motivation.

Everyday is an Etch-A-Sketch.



Sometimes, every hour is an Etch-A-Sketch.

And sometimes, every minute is an Etch-A-Sketch.


Happy New Year,
Gunny Mike

Friday, December 27, 2024

I Got Complacent—and Here’s What I Learned

 The Frog in the Beaker Parable:

If a frog is placed in a beaker of boiling water, it will immediately jump out to save itself. However, if the frog is placed in a beaker of lukewarm water that is slowly heated, the frog will remain in the water, not noticing the gradual rise in temperature. Eventually, the water will reach a boiling point, and the frog will perish because it failed to react to the slow, incremental change.

Moral of the Story:

The parable serves as a warning against complacency and the failure to act in the face of slow, incremental changes that can lead to disastrous outcomes. It’s a lesson often applied in business, personal life, or societal contexts, emphasizing the importance of staying vigilant, recognizing warning signs, and taking proactive steps to prevent negative outcomes.


My Story:

I spent most of 2024 in a beaker of  lukewarm water. If I'm honest with myself, it probably started in sometime in 2023. Perhaps even earlier than that. I had gotten complacent. I was totally unaware it was happening to me.

The first sign I realized something was wrong is when my July 2024 software payment from MyCommerce/Digital River was late. This had happened once before in October 2023. A quick email to support was all that was required. So, I sent off an email. I received a response saying they had put a new ticket system in place. I created an account and opened a ticket. And...crickets. 🦗

August turned into September, which turned into October. And now I'm missing July, August, and September payments. 

It was October and I started thinking about some of the other Delphi products I have purchased in the past and the user buying experience. I even sent Ray Konopka an email asking him what shopping cart system he put in place on https://www.raize.com/. Ray was gracious with his time and quickly responded.

It was at that point I realized this was not going to be a weekend just project. I also realized just how widespread the Digital River/MyCommerce/Share-It situation was. I wasn't the only one. 👇😓
 https://www.theregister.com/2024/10/15/digital_river_runs_dry_hasnt/

The solution I wanted was a Merchant of Record (MOR). I wanted someone else to handle all the interactions with customers. I just wanted to put links on my website to a shopping cart page.

Complacency Turned Into a Rabbit Hole 🐇🕳

I narrowed down my search to two MORs; FastSpring and Paddle. I crunched the numbers and decided to go with Paddle. I created an account with Paddle and submitted my website for verification.

 Your Website Has Been DENIED!

My website was denied with no specifics other than it did not meet Paddle's standards. So, I signed up with FastSpring. I was also denied by FastSpring.

Turns out that I did not have the adequate GDPR processes in place. I needed to severely update my website. I need to add a Consent Banner and all the necessary webpages; Terms of Service, Privacy Policy, Cookie Policy

The Consent Banner. Oh yeah that little popup thingy that lets visitors accept which cookies they want to allow. And one of those cookies is Google Analytics.

This lead me down the path of implementing Google Tag Manager. I ignored all the warning messages Google Analytics had bee showing me about the change to GTM. 

I'm a do it yourself kind of guy so I was looking for a "do it yourself consent banner." I settled on Klaro https://github.com/klaro-org

So I spent three whole weekends implementing Google Tag Manager, Klaro, and updating my website to interact with the new consent banner.

I added the three necessary webpages; Terms of ServicePrivacy PolicyCookie Policy and resubmitted to both Paddle and FastSpring. It took about a week to 10 days but I was now APPROVED!

Paddle

I started looking around the back-end in Paddle for how to set up a shopping cart with a download button. After several hours of reading the documentation I gave up. I sent an email to my sales rep asking for help. After several back and forth emails, it turns out that what I needed was "Paddle Classic" (a completely different system) from Paddle Billing. I gave up and switched over to FastSpring.

FastSpring

I found FastSpring to be very intuitive. And of course I was thoroughly testing all the pieces. I found a flaw in the "Invoice Email" which directly affects the download link. Unfortunately you cannot modify the email templates until your go live. The process of going live took another week to 10 days.

I finally got everything in place and ready to go just after Thanksgiving.

SEO vs AEO (Ask Engine Optimization)

Last week I discovered a few things.

I have found myself using ChatGPT more than Google when I want answers. Real answers. And last week I learned about Ask Engine Optimization (AEO). 

Is Search Engine Optimization (SEO) dead? Maybe? Maybe not? Read this post from Dave Collins at Software Promotions. https://www.softwarepromotions.com/news/seo-is-dead-again/

I also discovered https://www.perplexity.ai/ The first question I asked Perplexity was "Who are ZilchWork's direct competitors?"

I also found this fantastic website, Answer Socrates https://answersocrates.com/

Zilch - Complacent For Almost 7 Years

I haven't just been complacent, I've been asleep at the wheel. I've enjoyed a software product with a funny name "Zilch" for years. I noticed my sales have been steadily declining. I just assumed it was do to the look and feel of my current desktop software begin stuck in the 640 X 480 pixel mode. Wrong!

What I failed to notice was a modern product called Zilch was taking the world by storm. Zilch launched in 2018 (that's almost 7 years ago). It's not for paying off debt like my software... it's for buying products. It puts people in direct contact with products without using credit cards. 

Hopefully you can lean from some of my mistakes.

Use the comments and share how you have been complacent!

Enjoy!
Semper Fi
Gunny Mike
https://www.zilchworks.com

Saturday, September 14, 2024

Delphi Tip of the Day: The Delphi Magazine Total Collection

I'm always looking for ways to improve my Delphi skills. Sometimes, this takes me down a rabbit hole. And each time, these little side trips never answer "Yes" to the question "Will this help me ship?"  

Last week I went down the "global variables are bad" rabbit hole. 🐇🕳

Global Variables Are Bad

I opened my copy of "The Delphi Magazine Total Collection" looking for some inspiration. And, I found a 6 Part series called "Effective Delphi Class Engineering" written by David Baer. I'm slowly working my way through these articles.

Issue: 57 Effective Delphi Class Engineering 1:
Crossing The Chasm


David Baer kicks off a new series of articles aimed at all of us who are reluctant, confused or ill-informed on what object-oriented development is all about. The goal is to demonstrate, clearly and without jargon-loaded obfuscation, how to design, create and use Delphi classes to make your development more productive.
Issue: 59 Effective Delphi Class Engineering 2:
Welcome To The Machine


David Baer continues his series on practical object orientation by putting Delphi’s object machinery under a magnifying glass. He examines topics such as memory management, method calling, protocols and other compiler- related issues.
Issue: 60 Effective Delphi Class Engineering 3:
Skyrocketing Property


David Baer thinks properties are wonderful and this month gives us insights and advice on how they can best be put to use in our classes.
Issue: 62 Effective Delphi Class Engineering Part 4:
The TObject Of My


David Baer focuses on inheritance in this part of his popular series on object oriented development in Delphi.
Issue: 63 Effective Delphi Class Engineering Part 5:
You Are TEgg Man... I AM TWalrus


David Baer has not gone mad (though he may have been listening to too many old Beatles albums!): this instalment of his series continues his practical real-world discussion of polymorphism and inheritance.
Issue: 65 Effective Delphi Class Engineering Part 6:
To Talk Of Many Things


David Baer concludes his series on developing Delphi classes with a miscellany of sound advice, ranging from events to exceptions, RTTI and message handling.



Part 1 of Baer's series of articles, refenced short paper written by Marco Cantu called "When RAD is bad", which I found it on the internet archive. 

https://web.archive.org/web/20001120081900/http://community.borland.com/devnews/article/1,1714,10463,00.html  

But that's not all I found. I found a download link to the entire "The Delphi Magazine Total Collection Issues 1 - 139 (April 1995 to March 2007)"

https://archive.org/details/the-delphi-magazine-total-collection


Enjoy,
Semper Fi
Gunny Mike
https:\\zilchworks.com

Thursday, September 12, 2024

Sell Me This Pen!

OMG! I wish I had known this years ago. The Marine Corps taught me the Xerox Personal Selling Skills 3 (PSS3 = Needs Satisfaction) method. They turned me into a "regurgitator". If I had seen this video in 1994, it would have made a HUGE difference.



Show Me! Don't Tell Me!

HaveDemand your mentor model
the sales behavior for you!


Enjoy!
Semper Fi,
Gunny Mike
https:\\zilchworks.com


Sunday, September 1, 2024

Delphi Tip of the Day: How to Keep Your Code Folded in Delphi 12

I like the "Code Folding" feature of  Delphi. However, I noticed that every time I reopened a project in Delphi 12 where I had previously folded the code, the code was no longer folded.

To keep your code folded in Delphi 12 you need to turn on the Save project desktop when closing option inside the IDE.

Tools > Options > IDE > Saving and Recovering

This option is unchecked in the default, out-of-the-box setup.


Delphi 12 also includes a new feature called Save editor state when closing a tab any time
https://docwiki.embarcadero.com/RADStudio/Athens/en/Saving_and_Recovering

Save editor state when closing a tab any time When selected, the current state for the views is saved before closing it. State info includes collapsed regions, cursor/caret position, and bookmarks.

This allows you to close and reopen a tab within the same editing session, and when the tab is reopened it will display exactly as it was when it was closed. This is similar to the Save project desktop when closing setting but functions all the time, not just when closing and reopening a whole project.

This option can only be enabled when Save project desktop when closing is checked.

Let me know in the comments what other out-of-the-box tweaks you like to make to a brand new Delphi install.

Enjoy!
Semper Fi,
Gunny Mike
https://zilchworks.com