XojoScript debugging

if you’ve EVER tried to debug a Xojo Script its truly a pain in the rear end

Since one of my current projects requires a lot of Xojo Script that became really apparent and really annoying

So, for this project, we made a XojoScript debugger ๐Ÿ˜›
You can run & single step. And with each step the values of all variables in scope will be reported; where possible. Since there’s no introspection in XojoScript I cant make it dump out the values of properties of classes or other reference types ๐Ÿ™

But – here’s what it looks like so far ๐Ÿ˜›

INN

Over the last week I’ve been asked repeatedly about INN’s status
So I’ll post the same answer I’ve give n out several times

It seems to have been aย series of bad luck & timing

Garry was in the process of transferring operation of INN to me
Just as  I was going on holidays

And apparently Digital Ocean had a node failure and thats where INN was housedAs far as I know Garry hasnโ€™t investigated or invested any time to get it back up and running since he was moving away from being the admin anyway

And Iโ€™ve been on hotel wifi so couldnโ€™t get anything done

The intent IS to get the domain transferred and the discourse instance back up and running as quickly as possible

UPDATE : I am HOPING that once the domain transfers that INN will be back up
That could be later this week after Nov 23
Fingers crossed !

Graphics in C# on macOS

The Einhugur framework has similarities to Xojo in many ways

It has a Canvas, just like Xojo

And when you use its paint event you can do many of the same things like drawing text and shapes and pictures.

We can add a canvas just like other controls. And we can implement the paint event in the same way.

canvas = new Canvas(left,top,width,height);
canvas.Paint += canvas_Paint;

And the paint event would look like

private void canvas_Paint(object sender, PaintEventArgs args)
{
    GraphicsContext g = args.Graphics;

    // GraphicsContext is in many respect like Xojo's
    // Graphics

}

Now you can change the fill colors, stroke colors (borders), and draw shapes & text. You also have built in rotation, clipping, and scaling. There are no bezier paths and some more complex drawing operations – yet.

One thing you will notice is that getting an RGB or RGBA color is a little different.
Since colors in the Einhugur framework are based on CGColors internally they permit a really wide range of colors. Much more than the 0 – 255 based Xojo colors.
So, each component of a RGB color is a floating point value in the range 0 – 1 like the following

g.FillColor = Einhugur.Drawing.Color.RGB((nfloat).6, (nfloat).3, (nfloat).4);

RGBA is similar with the Alpha also being a value ni the range 0 – 1.

Once you have the basics in place you can draw most anything you want.

private void canvas_Paint(object sender, PaintEventArgs args)
{
   GraphicsContext g = args.Graphics;

   g.FillColor = 
     Einhugur.Drawing.Color.RGB((nfloat).6, (nfloat).3, (nfloat).4);

   g.StrokeColor = 
     Einhugur.Drawing.Color.RGB((nfloat)0, (nfloat)1.0, (nfloat)0);

   g.DrawRoundRectangle(1, 1, 
         (float)(canvas.Width - 2), (float)(canvas.Height - 2),
         4, 4);
}

Oh and yes, with creativity you can combine drawing pictures with threads !

As usual a link to the project as it is now

Hanging on by a …

THREAD !!!!!!!!!!

yeah ok bad joke. I’ve been so dang busy with studying and work that I just haven’t had a reasonable chance to write any updates for the C# on macOS series.

But now that my Canadian Ski Patrol exams are done I can get back to some fun.

How to make our little project use a thread instead of a timer. The biggest place in the project you might notice this is in the level indicator.

Right now when you press & hold a menu item the updates to the level indicator will pause until you release the menu item. It sure would be nice to not have that occur.

And, the reality is that since we are using C#, most of what we need is already built in, or easy to acquire.

We’ll need to add a Nuget package

We’ll need to add the Xamarin Essentials package

And we’ll want to add a using clause so the compiler is alerted to the fact we’re going to use the Xamarin.Essentials package.

We need to declare a variable to hold out thread instance

We’ll change the window SetUpControl method to NOT create a timer but instead create a Thread.

This new line creates the thread and tell it what method to call when the thread runs. This method is one that gets called ASYNCHRONOUSLY – so it has some slightly special set up.

 private async void Thread_Action()
 {
    while (true)
    {
       await Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync( () =>      Update_Indicator() );
       System.Threading.Thread.Sleep(100);
    }
}

Note the ASYNC keyword on this method – thats the entire “special set up” ๐Ÿ™‚

The other thing I’ve done is refactored the old timer code so the thread and timer can both use the same method to update the indicator.

The only remaining thing to do now is start the thread running right where we used to have the Timer getting started.

Now because we have added some C# runtime references, and a using clause for System.Threading, you may see an error like

You can have VS take you right to the location of the error by right clicking the error and choosing “Go To Task”

We can correct the issue by simply fully qualifying the Type name to Einhugur.Threading.Timer

Once fixed you should be able to run and, note what when you press & hold the Edit item in the menu bar the level indicator continues to move up & down unlike what it did with the timer.

The speed with which the indicator moves up and down can be adjusted by changing the sleep value for he thread. The shorter the sleep period the faster indicator will update.

Once again – the project in its current state

Lions and Timers and Such ! Oh My !

Anyone following along that has poked around what exists for the Einhugur C# UI Framework should notice that there IS a Timer object in there already.

Since its in the Einhugur.Threading namespace we need to add that using clause to our project

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using AppKit;
using CloudKit;
using Einhugur.Forms;
using Einhugur.Threading; // <<<<<<<<<<<<<<<

using Mono.Data.Sqlite;
using Npgsql;

Using one is as simple as declaring the property for it, creating it, setting its period, or interval, and adding a method for it to call whenever the Timer needs to run some action.

            timer = new Timer();
            timer.Interval = 0.05;
            timer.Action += timer_Action;

One thing you dont need to do, since its not a visual control, is add it to the list of controls in SetUpControls. Since its actually a property on the layout thats enough for it to function exactly as we want.

However a timer by itself isn’t very interesting. Let’s have it drive something visual like a Level Indicator.

    TextField textfield1;
    TextField textfield2;
    ListBox list;
    Button pushButton;
    Timer timer;
    LevelIndicator indicator;

We’ll want to add one more using clause to access the Einhugur Drawing namespace where things like color and gb functions are defined

using Einhugur.Drawing;

And then in SetupControls we need to add code to set the indicator up

indicator = new LevelIndicator((float)(pushButton.Left + pushButton.Width + 12), (float)pushButton.Top, 200, 22);
indicator.Style = LevelIndicator.LevelIndicatorStyle.DiscreteCapacity;
indicator.CriticalFillColor = Color.RGB(255, 0, 0);
indicator.WarningFillColor = Color.RGB(0, 0, 255);
indicator.FillColor = Color.RGB(0, 0, 0);
indicator.MinValue = 0;
indicator.MaxValue = 100;
indicator.WarningValue = indicator.MinValue + (0.50 * (indicator.MaxValue - indicator.MinValue));
indicator.CriticalValue = indicator.MinValue + (0.90 * (indicator.MaxValue - indicator.MinValue));
indicator.Value = 0;

return new Control[] { textfield1, textfield2, 
                         list, pushButton, indicator };

Indicators come in several styles. They are explained on this Apple page. But they are easy to play with. One gives you a segmented capacity, like an audio meter, one a continuous bar that has not marked gradation, one shows as a star rating. Try them all ๐Ÿ™‚

Certain settings, like critical fill color warning fill color, warning value and critical value may not make sense with some styles.

If you use the discrete and continue capacity styles they do. And when the value of the level indicator is above the warning, and less than critical that portion of the indicator in the warning color. Same for critical. We’ll set all these up and hook it to a timer that will reveal what I mean.

Using the settings above now all we need is the timer action method to do something to the level indicator. Lets make it count up and down to animate the level indicator.

 private int increment = 1;
 private void timer_Action(object sender, EventArgs a)
 {
   if (indicator.Value <= indicator.MinValue)
   {
      // reverse and go up 
      increment = 1;
   }
   else if (indicator.Value >= indicator.MaxValue)
   {
      // reverse & go down
      increment = -1;
   }
  
   // change the level indicator
   indicator.Value = indicator.Value + increment;
 }

OK we have most everything set up. Instead of hooking this timer up to start when we push the button on our layout, which would be simple, lets start it when the window opens.

We dont want to put the call to the timers start method in the Setup of the controls. So how do we get this into what would be the equivalent of the Open event ?

If you right click on “Window” in our definition of the class

	public class MainWindow : Window

and select “Go To Definition”

you get the assembly browser. In there you can see that a Window has an Opening method we can make use of. Perfect !

To override the default implementation we need to tell the compiler this IS an override

 protected override void Opening()
 {
    timer.Start();
 }

Often the easiest way to get the right definition for the method you want to override is to copy the declaration from the assembly browser, paste it into your code and change virtual to override.

And now as the timer runs its action event it affects the value of the level indicator. On the way up as the level indicator gets to the warning value the color changes to the warning fill color. And when it gets to the critical value it again changes. And as it goes back down in value the colors change again.

Again – our project as it is now

Using other databases in C#

A new version of the Einhugur C# UI framework was released a short while ago.

Since the framework is still literally a work in progress some changes an dupes are to be expected. Listbox now exists and its constructor now takes an array of column titles as well as the initial dimensions. So you may need to update code like


list = new ListBox(10, 20, 80, 20 );

to add a new last parameter

list = new ListBox(10, 20, 80, 20, new string[] {"col 1", "col 2"} );

to set the column titles.

Dont be surprised won the road if there are several constructors to pick from where you dont have to set the titles right then.

With that out of the way lets turn to using the Mono.SQLite database – with one on disk !

In prior editions of the tutorial we used the in memory SQLite database. We had

sqlite_conn = new SqliteConnection("Data Source=:memory:");

To switch this to use a database on disk we just need to alter the connection string.

  sqlite_conn = new SqliteConnection("URI=file:/Users/npalardy/testdb.sqlite;");

With the Mono driver for SQLite when you connect this will create the database if it doesnt already exist.

And .. tada ! Thats it ๐Ÿ™‚ Instead of an in memory database now we are using one from disk.
Here’s the project as it exists so far.

In the poll I posted half the respondents ๐Ÿ˜›Sia they wanted to see how to use a different db. So we’ll alter this to use PostgreSQL since I happen to have a handy configuration already on my machine – but the steps will be similar for most databases.

First we need to grab a PostgreSQL database driver. We’ll add a NuGet package for this. Right click on Packages

We can filter using the field in the upper right to quickly find relevant packages

Note there are many PostgreSQL packages we can pick from. I honestly dont know all the pro’s and cons of the different packages. I have used the Nppqsql package ands so far it works as I need & expect.

Select that package and add it to the project. You may see several other packages also get aded. When a package depends on another to be able to work the packages that are depended on are also brought in automatically.

In Xojo terms we’ve basically added a “plugin” – but only to this project. Projects in VS have “per project plugins”

In our code we’ll need to addd a using clause to let the compiler know it should expect references to this new plugin in this code.

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using CloudKit;
using Einhugur.Forms;

using Mono.Data.Sqlite;
using Npgsql; // <<<<<<<<<<<<<<<<<

As well we need to adjust our connection so instead of using SQLite it uses PostgreSQL.

 // I deliberately left the variable name the same so you can see how
 // little needs adjustment

 // Mono.Data.Sqlite.SqliteConnection sqlite_conn;
 NpgsqlConnection sqlite_conn;

And the code where we create the connection needs to connect to the server

// sqlite_conn = 
// new SqliteConnection("URI=file:/Users/npalardy/testdb.sqlite;");

sqlite_conn = 
new NpgsqlConnection("Host=localhost;Username=XXXX;Password=XXXX;Database=norm_csharp");

The ONE other things we have to account for, since we’re using raw SQL. While the following will work for SQLite it wont work for PostgreSQL.

IDbCommand dbcmd = sqlite_conn.CreateCommand();
string sql = "create table if not exists employee ( firstname, lastname )";

SQLite is OK with an untyped create statement. PostgreSQL isn’t. So we do need to alter that as well.

IDbCommand dbcmd = sqlite_conn.CreateCommand();
string sql = "create table if not exists employee ( firstname varchar(50), lastname varchar(50) )";

And with that change everything should work again and now were using PostreSQL.

We could use a more generic data type for the now badly named sqlite_conn. Something more akin to Xojo’s Database. We could declare it as

            System.Data.IDbConnection sqlite_conn;

And our code could create & assign either a new sqlite connection or PostgreSQL one

Here’s the project as it exists so far.

C# updates

If you’ve been following along with my C# series you should be able to open your copy of the app we’ve been creating and update the Einhugur Forms nuget package.

This brings along some new controls to use as and some additions to existing ones

You’ll see there’s a dat picker, disclosure triangle, combobox and additions to the listbox for headers.

We’re still not to a “1.0 version” but we are working on moving things ahead as we can

Dont hesitate to note if there’s something specific you need, or see missing.

That kind of feedback is useful as heck

Watch what they do

What we as users get told is “report your issues, upvote them as this influences priorities”
So many do ; or did. I’ve got far too many people telling me I just gave up reporting them as they never get fixed. From names that if I listed them would surprise people.

Since I still use Xojo for client projects I report bugs and tell my clients to advocate for them getting fixed.

Great !

So report them upvote them and … they dont get put on a milestone to get fixed ?

There are several open bugs with more upvotes than open reports that are assigned to milestones

The top 3 open bugs have higher popularity than the items assigned to 2022r4

The top 6 open bugs are at least the same popularity as the top two items assigned to 2022r4

Trust me I know the “dodge” that gets rolled out Its not the only criteria we use. Sure but what criteria DO get used ? How else do you judge how many people might be affected if not by upvotes ? The IDE doesn’t report back how many people use XYZ in their code so how else can you judge the impact ? The number of duplicate reports ? Even Issues isn’t any better at detecting those than any prior system was.

Personally I’d like a less “hand wavy ignore the man behind the curtain” way of knowing how to influence priorities. Make upvotes ACTUALLY count for what gets put into a milestone. Clear prioritization criteria would be VERY welcome.

As I’ve often been told “Watch what they do. Not what they say.”
We’re told to report upvote etc
Yet that isn’t what we see getting addressed

I can see why people just give up

Tired of adding strings ?

If you’ve ever had to write a lot of output with strings you’ve probably had to concatenate them.

In VB you used &. In Xojo you use + and more than likely Str, Format, and the newer ToString.

Eventually when you write enough code you end up with things that look like

Var Explanation as string = "Hint: If you don't save," _
  + " you will lose your work" _
  + " since your last Save."

You use the line continuation characters and spread it across multiple lines. And if you need to actually insert user generated vales you end up with code that gets increasingly hard to read

Var Explanation as string = "Hint: If you don't " _
  + action _
  + "," _
  + " you will lose your work" _
  + " since your last" _
  + action _
  + "."

If you have to add in numbers or other items that require the use of Str, Format, ToString, etc it gets cumbersome*

What I’ve become really enamoured with in many other languages is a thing called string interpolation.

In C# the previous example might look like

string Explanation = $"Hint: If you don't {action}, you will lose your work since your last {action}."

I find this quite a bit easier to read. Note the $ before the first quit – this is the indicator to the compiler this string should be interpolated. When that occurs the runtime will replace {action} with the contents of a variable in scope and insert it right there !

C# has a TON of options for dealing with strings in many different ways (and there’s a fun interactive demo to messagings around with too)

Perhaps one of the most useful is multiline string literals

string rawStringLiteralDelimiter = """"
    Raw string literals are delimited 
    by a string of at least three double quotes,
    like this: """
    """";

Console.WriteLine(rawStringLiteralDelimiter);

will output – end of line and everything

You might be wondering What if what I want to insert isn’t a string ?

That still works too !

string action = "save";
int foo = 90;

string Explanation = $"Hint: If you don't {action}, you will lose your work since your last {foo}.";

Console.WriteLine(Explanation);

would output

Its very handy and very powerful as there are all kinds of formatting options you can use in interpolated strings.

And you can get away from writing + ๐Ÿ™‚

* I have written code where my own classes have operator_convert to automagically turn themselves into a string and that can make life a bit easier.
It just doesnt happen with built in intrinsic types in Xojo. You can’t write :

dim I as integer
dim d as date
dim s as string = "Today," + d + " we counted " + I + "twiddles"

There are some interesting StringBuilder implementations but its still much more cumbersome than interpolation in many cases.