adventuresinfpc
adventuresinfpc
Adventures in Delphi / FPC
7 posts
My rapid journey through Lazarus / FPC programming landscape
Don't wanna be here? Send us removal request.
adventuresinfpc · 2 years ago
Text
Structs, Arrays, Matrices … [part 2]
Consider a class definition:
TAdvancedDropDownList = class public       currPos   :Integer;       items     :Array of String; constructor Create(entryItems :Array of String); end; implementation { TAdvancedDropDownList } constructor TAdvancedDropDownList.Create(entryItems:Array of String); begin   items := entryItems;   end;
Call this with:
procedure TForm1.FormCreate(Sender: TObject); var   items         :Array of String; begin   items         :=['Lorem','ipsum','dolor','sit','amet', 'consetetur','sadipscing','elitr','sed', 'diam nonumy eirmod tempor invidunt', 'ut labore et', 'dolore','magna aliquyam erat', 'sed','diam','voluptua'];   TAdvancedDropDown.TAdvancedDropDownList.Create(items); end;
This is not a very god minimum working example. I cut off the unnecessary bits (in context of this post). This will fail. Error Message is :
Error: Incompatible types: got "{Open} Array Of AnsiString" expected "TAdvancedDropDownList.{Dynamic} Array Of AnsiString"
HHHMPH. Turns out, I have to use this trick.
type TStringArray = Array of String; { TAdvancedDropDownList } TAdvancedDropDownList = class public       currPos   :Integer; items     :TStringArray; constructor Create(entryItems :Array of String); end; implementation { TAdvancedDropDownList } constructor TAdvancedDropDownList.Create(entryItems:Array of String); begin   items := entryItems;   end;
The changes are shown in orange. If I use the type of the argument (violet line in all examples) to the constructor as an Array of String, (it is expecting as such), then the supplied and try to set an Array of String inside the constructor using the said argument, it will fail.
It appears, that the type of the argument to the function (here the constructor), even tho is an Array of String, it is different than the type of a class variable, which is also defined as Array of String. The reason, as I understand is :
The former is an array of unspecified length, but immutable (Open Array)
The later is a mutable array of unspecified length that can add or remove elements (Dynamic Array).
Even tho, both are Array of String, we need a method to differentiate these. So, the current syntax of Lazarus / FPC requires the mutable class variable to have a different type signature.
This is done by creating a new type which is also an Array of String, and then setting the class variable to this type.
TStringArray = Array of String;
I do not understand the complete story here. But I am told in the forum, that this is the syntax now, and people use autopilot to work through this.
Okey .......
0 notes
adventuresinfpc · 2 years ago
Text
Structs, Arrays, Matrices ... [part 1]
I have been homeless a few times over the last few months, so I couldn't write anything ...
Now, I am back to this project, and want to put work in it.
Arrays
In delphi / FPC arrays are funny things.
In most languages, arrays have natural numbers as their index. For example, in C, one can write:
int arr[20];
This will create an array of 20 integers. In C, generally, array lengths must be known at compile time. The elements of the array each have a dedicated identifier, called index. These are natural numbers (integers) starting at 0.
So, assume that the array was filled with values 1,2,3,4,5,6 ... all the way up to 20, in that order. Now, the first element in the array is 1, the second one is 2, etc ... ending at the 20th element which is 20.
The first element can be accessed by inquiring the 0-th index of the array. Thus
arr[0]
would return 1. this »1«, inside the array, has the unique ID of 0. If this »1« was overwritten by the value of 100, then the new value, the »100« would carry the ID of 0.
Similarly, the 20th index is given by 19, which in turn means that
arr[19]
would return 20.
In case of C, we do not call the first element of the array the first element. We call it the 0th element. Many languages behave this way, and many others do call the first element the first element indeed.
We notice, that the array indexes usually start at a predetermined point, be it 0 or 1.
In Pascal however, we can declare the indices of an array.
We can write:
varArr: array [-3 .. 3] of Integer;
Here, the first index of the array will be -3. Note the double dot representing the range of the indices in -3 .. 3
It is also possible to declare a new type with custom indices, like so:
level = array[-24..24] of longint;
Multidimensional arrays can be done like so:
box = array[-1..1, -1..1, -1..1] of boolean;
Multidimensional arrays can be jagged, i.e. subarrays do not have to be of the same size.
0 notes
adventuresinfpc · 2 years ago
Text
POINTERS !!!!
Well, Pointers are supposed to be everywhere, in every languages.... (almost). Even C has it. But, i recall, that some version(s) of Basic does (do) not have it.
In any case, the pointers of Lazarus takes inspiration from Delphi and FreePascal is also there.
Delphi
Delphi is a Strongly typed language. Thus, variables must come with an associated type. The type assignment is done via the : (colon) operator. (I will discuss about some quirks of Types as well in a later post).
Example :
VariableName : Variable Type;
More concretely :
intVariable : Integer;
To make a pointer, we use the ^ (caret) operator in front of the Type name.
intVariablePointer : ^Integer;
Now intVariablePointer is pointing to a memory location, where an integer is stored. To get the actual value (dereference), we again use the same ^ operator - but this time at the end of the Variable Name.
So, we can say :
intVariable : Integer;
intVarPointer : ^Integer; //^ in front of the type name
and then later,
intVariable := intVarPointer^ ; // at the end of the Variable name
Now, the dereference is extracting a raw value out of the address. The raw value is neither an address, nor a Variable. Therefore, it can't be used as a target of an assignment.
This is not a valid statement.
intVarPointer^ := 5;
The left hand side already is an integer. It may be something like 10 or 42, namely the integer value that was originally inside the address held in the pointer. That means, it is not a variable. So a value of 5 can't be assigned to it.
To get the address of a variable, use the @ operator in front of the Variable name. Example :
intVarPointer := @intVariable ;
This will work.
Pointers can be made typeless. This is because all pointers themselves are 4 or 8 bytes of memory (depending on the CPU or Operating system). This is done by a compiler switch (another topic to discuss later).
The switch to untype a pointer:
It is the {T-} switch. This will ensure that no pointer carries an associated type information. As long as the target value(s) are of the same size,one can be converted to another. So this would work, if the {T-} switch is used:
charPointer : ^PAnsiChar;
bytePointer : ^PByte;
bytePointer := charPointer; // both one byte long
In the current Delphi implementation, the generic PChar is a pointer to a widechar. So, I specifically used a PAnsiChar .
The switch to type a pointer:
It is the {T+} switch. This will ensure that all pointers carry an associated type information. This would make the above char Pointer to Byte Pointer impossible.
Delphi Allows Pointers to Variant types, Currency types and many more funny things, which I will deep dive later on.
FreePascal
This could potentially apply to Delphi as well - But I understood these things in a FreePascal context.
Nil
Pointers as nil-able, i.e. can be set to Nil. Nil associates a default bottom value, that can't be a valid address. So if a pointer is Nil, it can be investigated for a Nil value. Conditions like if pointerVar = Nil then, actually work. The CPU can check against such a bottom value.
This bottom value then serves as a flag, to indicate that because the pointer contains an invalid address, it was not associated to any existing variable.
However, in FreePascal Nil has many other context dependent meanings. I will discuss that in detail later again.
Lazarus includes all these things. But it becomes quite interesting in the topic of pointer arithmetic and Record Pointers. My next topic will be Record Pointers.
0 notes
adventuresinfpc · 2 years ago
Text
The Menu Item Struct
Creating a struct in Lazarus / FPC is done using a type declaration.
In FPC, a variable is declared with the colon. Example:
varname : vartype ;
i : Integer:
This causes the compiler to create a variable i of type Integer. This variable is allocated to the stack.
A variable is defined with a colon equals. Example:
i := 10;
This way, the value of i is set to 10.
For a type, we use the equal sign while defining a new, user defined one. Types are defined at the top of the *.pas file, in the Type region. The pascal file contains regions, from top to bottom :
unit (followed by file name, which is also the name of the program unit)
mode switches (which tells the compiler to change its behavior)
interface (which now breaks down to the following:)
uses (list of other units that is used by this one, i.e. the include files)
type (this is where the type definitions go)
implementation (this is where the global variables, and the procedure definitions go)
In the type section, we write:
stringNodeStruct = packed record ID : Integer; name : String; stringVal : String; Parent : strNodePtr; Children : Array of strNodePtr; prev : strNodePtr; next : strNodePtr; end;
The first line defines a new type (an user defined type). Note the use of the equal sign. The record command sets makes the struct. The packed command forced the compiler to use as little memory as possible. Otherwise, the compiler will align everything to full word boundaries, for faster access.
Since we have a doubly linked list, we also need to use pointers to the previous and the next element, as well as, for our case, addresses to parent and children.
We use strNodePtr for this. I will discuss about pointers in the next post.
0 notes
adventuresinfpc · 2 years ago
Text
Menu Design 001
I want to use OOP design patterns.
The entire menu should be one object.
In this object, I want to be easily able to access the first and the last items, and go forward or backward from them. This "inspires" me to use Doubly Linked lists. Here is the summary
The Menu Object
The baseline will be the Main Menu. This is the menu that I can render at the very top of the application. This, as an object is a doubly linked list.
I pack it in a class, with the following variables :
Root
First
Last
The root and the first element can be the same element, but does not have to be. On the other hand, it would have been sufficient to only have the root element.
Each element is a struct, that contains an item of the main menu, the address to the main menu item before it, and the item after it.
There are also various methods, for adding and removing additional menu items or submenu items.
The Menu Item Object
Each menu item is a struct. In Pascal / Lazarus, this is a Packed Record. The definition is:
stringNodeStruct = packed record ID : Integer; name : String; stringVal : String; Parent : strNodePtr; Children : Array of strNodePtr; prev : strNodePtr; next : strNodePtr; end;
I am currently denoting this as a string node, not a menu node, because the important content is just the name of the menu, which is a string.
The nodes contain an item children, for submenu items. Symmetrically, there is also a parent. There are the prev and next items, as expected from a doubly linked list.
The children, parent, prev and next are pointers.
In my next post, we will investigate the Menu Item object in detail.
0 notes
adventuresinfpc · 2 years ago
Text
Menu Conundrums
One of the big problems I am suffering from is:
I am on Linux. Details :
❯ pacman -Q qt6-base qt6-base 6.4.2-1.1
❯ uname -a Linux █ █ █ █ █ █   6.1.11-1-cachyos #1 SMP PREEMPT_DYNAMIC Thu, 09 Feb 2023 14:06:43 +0000 x86_64 GNU/Linux
I am running the Emerald theme, that looks like this:
Tumblr media
If I make a Lazarus application, the menu however looks like this :
Tumblr media
The menu is black. It is not legible.
The usual method is to set the ownerDraw property of the menu to be set to true, then something like this:
procedure TForm1.MainMenu1DrawItem(Sender: TObject; ACanvas: TCanvas;  ARect: TRect; AState: TOwnerDrawState); begin  showMessage('1');  ACanvas.Brush.Color := clBlack;  ACanvas.FillRect(ARect);  ACanvas.Font.Color := clYellow;  ACanvas.TextOut(ARect.Left, ARect.Top, 'TEST'); end; procedure TForm1.MenuItem1DrawItem(Sender: TObject; ACanvas: TCanvas;  ARect: TRect; AState: TOwnerDrawState); var  s: string; begin  showMessage('2');  ACanvas.Brush.Color := clBlack;  ACanvas.FillRect(ARect);  ACanvas.Font.Color := clYellow;  ACanvas.TextOut(ARect.Left, ARect.Top, TMenuItem(Sender).Caption); end;     
But in my case, this did not work. In Windows, there is the doDrawItem call, but not on linux.
So one thing I gotta do is: create my own Menu Widget.
0 notes
adventuresinfpc · 2 years ago
Text
Goal
I want to write two linux apps.
App #1 : A note taking app - which supports:
Custom Syntax Highlighting
Markdown + Colors
Programmable text layout, with better control than CSS / HTML and other bs
App #2 : A Calendar app, similar to KOrganizer, but with these enhancements:
Count total number of hours in a particular calendar
“Repeat unless” functions
Better subproject organization.
The very important part here is to rapidly develop the system. Lets consider the system in detail.
App #1 is called NoteBook.
The Goal of notebook is to organize my thoughts around the design of a custom Drone. I am designing a new drone, with genetic algorithm. My thoughts begin with some pseudo-ish code(s) like this:
Tumblr media
Of course, the image is a render from GNU TeXmacs. But the point is, I want to quickly see an overview of various keywords, and elements of the pseudo-ish code. For this, I need a system, where I can define specific text-blocks - with or without additional logic - as targets of highlighting, and add some highlight commands - such as colors or font weight.
This sounds simple in word, but is considerably difficult to implement. This is one of the topics I will discuss.
In addition, it should also support markdown syntax - such that comments inside this pseudo-ish code can be written as markdown.
In practice, I wanted to use a two pane markdown editor anyways. But it did not quite work out, as markdown does not support colors inherently. Some editors let an inline HTML <span> tag, but that is very tedious to remember and repeat the same style over multiple occurrences of the same element or keyword. I could potentially hack one of those things, but I do not like it.
In addition, I also want various blocks of text to be arranged in a way that someone is reminiscent of a flowchart. I could do this with JS/CSS, but i really really abhor the combination.
So the Notebook App should be a two pane (actually three pane) layout.
On the leftmost, I should have global format controls, such as rendered document background color, etc. In the middle pane, I will be supplying plain text writing. This can contain the pseudo-ish code, formatting commands, formatting logic, comments ... etc. On the right hand pane the results will be rendered.
Structurally, it will have:
A block identifier engine. This identifies, if I have written an actual pseudo-ish code, or a formatting logic or a formatting command.
A layout engine. This creates an empty layout with placeholders, where the text may be inserted.
A code extraction and interpreter engine. This will extract and interpret the code from the blocks identified by the block identifier engine, and produce formatting commands, that the render engine can understand. This way, if I later change the render engine, then I only have to modify this component - and I can still reuse the other components.
A formatting engine. This will insert the formatting commands in the text / media to me rendered.
A rendering engine. Finally, this will insert the final renderable text / media to the placeholders created by the layout engine.
In picture:
Tumblr media
----------------------------------------------------------------------------------------------
App #2 is called the calendar
Start with a picture: 
Tumblr media
This is done in KOrganizer.
First of all, all tasks in a single color belong to a single calendar. But there is no way to compute the total time spent in a single calendar per week / per month etc. I need a system that can do it.
Also, in KOrganizer, I can say, that a event ( a Routine Item) repeats every week or every month or so. What happens if I am to say, that the item will repeat every week besides for the last week of the month? There is no easy way of doing this, unless you delete each those events manually over all the months you need.
I need a system that can automatically handle these exceptions.
Finally - I want to add “subevents”.
For example, in the image, I am farming Scorpions every Tuesday daytime till 1500 and drinking orange Juice every Thursday daytime till 1315. But I want to farm Akrav israchanani one week, and in another week Reddyanus assamensis. I should be able to somehow supply this information. I want an additional text in the entry "Scorpion Farming", as well as a mouse hover bubble, that shows the additional information. That Is to say, if a parent class of task that repeats every week, but the instance each week is slightly different - then the difference should be visible some way.
FPC
I want a native UI toolkit. I dont want to use GTK or QT, they are too bloated, and I also dont like GAMBAS for a task like this. So I wanted to resharpen my skills in Delphi / FPC, using the Lazarus IDE.
0 notes