Of bounds and positions

Windows have two sets of properties that all relate to positioning a window.

However, they are not all quite created equally.

There are, of course, the typical top, left, width and height properties. And also the “bounds” property which is a Rect.

If you examine the bounds property for a Document window, and the top, left, width and height you will find that the Bounds.top is not the same as the top property value. Nor is the height. Now why is that ?

In the following image the BOUNDS are the area enclosed by the red rectangle. And the top, left, width and height properties describe the area in light blue.

If you only had the top, left, width and height properties to use to position a window you would have to somehow figure out what the real size of the window was and account for the title bar size and possibly the outer window frame size. There may or may not be one depending on platform and window type.

And if you add a toolbar this further complicates that. The following image is the same window with a toolbar and once again marked with a red rectangle around the bounds and the blue area is the rectangle described by the top, left, width and height properties.

If, for some reason, you want to know the height of the title bar you can use the difference between the bounds top and the windows top property to see how tall it is.

Note that you cant use this difference to know how tall the title bar and toolbar independently. And toolbars dont appear to propertly report their top, left, width, or height at runtime. 🙁

Still the difference between the bounds properties and the windows other properties will let you determine how tall the title bar + any toolbar is.

Careful with those bounds out there.

Generics

One of the things that Xojo lacks is the notion of generics.

So what are these things and why would they be useful ?

In many programming languages you might want to define a class that behaves like a List. But you want to be able to make this generic enough that when you go to use one you can make a List of Strings, a List of Classes, a List of controls etc.

Right now the only way to do this in Xojo is to make all the the parameters and return values be variants in the interface definition. The downside to this is that you lose all compile time type checking and have to rely solely on runtime checks YOU put in the code.

If you could declare a List variable like

Dim myStringList as List<String>

This would indicate that the list should use String as the “generic type” for all the method parameters and return types. The interface declaration might have to change to something like

Interface List<Type>

  Sub AddRow(ParamArray values() as <Type>)
  End Sub
  
  Sub AddRowAt(ParamArray values() as <Type>, zeroBasedInxed as integer)
  End Sub
  
  Sub FirstRowIndex() as integer
  End Sub
  
  Sub LastAddedRowIndex() as integer
  End Sub
  
  Sub LastRowIndex() as integer
  End Sub
  
  Sub RemoveAllRows()
  End Sub
  
  Sub RemoveRowAt(zeroBasedIndex as integer)
  End Sub
  
  Sub RowCount() as integer
  End Sub
  
  Sub RowTag() as Variant
  End Sub
  
  Sub RowTagAt(zeroBasedIndex as integer) as <Type>
  End Sub
  
  Sub RowValue() as <Type>
  End Sub
  
  Sub RowValueAt(zeroBasedIndex as integer) as <Type>
  End Sub
  
  Sub SelectedRowCount() as Integer
  End Sub
  
  Sub SelectedRowIndex() as integer
  End Sub
End Interface

And now we have a generic interface AND a way to define a list that will, at compile time, have a specific and known type so the compiler can detect any incompatible type errors.

This would make interfaces even more useful than they are now.

Good habits when creating custom controls

Suppose you have the need to create a custom control like I did recently

One of the things that you should do so people do not get confused about using your control is to “implement” any events in whatever you use as your base class that should not be exposed to end users of your control. If you dont inplement these events then a user could, and that might end up in surprising behaviour in your carefully crafted control.

If you dont implement the Open event for your custom control a user could put an instance on a layout and implement that event. If this causes problems than you can make it so they cannot implement the Open event simply by adding that event handler to your custom control.

There may be events, like ConstructContextualMenu, DragEnter, DragMove, etc that make no sense for your custom control and so implementing them in your class would make it so users cant.

And this should make your custom controls easier for others to use.

But I’m entitled to …

When I give code away, for free, I’ve probably already invested a bit of time in it. How much time I’ve invested will vary depending on why I originally created whatever it is I’m giving away.

And often I will update the code. Sometimes to meet my own needs. Sometimes to meet a clients needs. And sometimes the code just sits for a long time without getting updated or touched.

And then I get someone saying “but you gave me this code it’s your responsibility to update it”.

Ummm ….. well my standard disclaimer is

All code is supplied on an AS IS basis.

I give it away. I don’t charge you for it or the time I’ve put into it. If its helpful then great. If not well I’m sorry for that. But that also doesnt mean I’m obliged to tweak the code to meet your requirements. Nor am I on the hook to fix any and all bugs you might find. It’s why I give full source code for you to do with it as you please.

It’s a gift. Accept it as offered.

Or hire me to tweak it to meet your needs.

Bevelbutton redux

At the end of June I posted about a replacement for the bevel button that I’d created.

Since then I’ve had some feedback and some updates & fixes submitted for it and a newer versions has been posted.

If you’ve used it in your projects you might want to grab the latest version.

Delegates

The Xojo docs about delegates are quite sparse about what you can or cannot do with them and whether they can or cannot take certain kinds of parameters. What they do say is that

A Delegate data type is an object representing a specific method. It is a function pointer with a method signature.

I was recently asked if a delegate that did not make use of any external dynamic library could take an object parameter. The delegate definition and the code creating the delegate are all inside a single Xojo project.

Delegates are kind of esoteric but like many things, when you need one you need one and it may be the only way to do what it is you want to do.

Inside a single Xojo project “delegation” can be done in several ways. Before Delegates what you might often find that an interface would be used. This would work for code all in the same project, but could lead to a lot of interfaces with one method just to be able to declare the delegate. When you use a delegate definition and AddressOf to create the delegate the difference is negligible. In both cases you define a new type, either the interface or the delegate, and then in some way have to implement that type so you can make use of it.

One key difference is that with an interface you can’t just use it with any method that has the proper signature. It has to be implemented by a class and then you need an instance of that class. So there can be more work with an interface in this case.

But notice I wrote that both a Delegate and and Interface define a new data type. What that means is that you can use the delegate name in a DIM statement just like you would use Integer, String, Color, Text etc.

dim delegateReference as MydelegateType

And then you can assign values to it – but in the case of a delegate you need to make sure you assign values that match the signature the delegate was defined with. This is the same as if you declare a variable as an integer you can’t assign a string to it.

For instance if we had the following :

Delegate NoParamDelegate() 
Delegate OneIntParamDelegate(i as integer)

Sub NoParamMethod()
End Sub
Sub OneParamMethod(i as integer)
End Sub
Sub InvalidOneParmMethod(s as string)
End Sub

dim noParam as NoParamDelegate
dim oneParam as OneIntParamDelegate

We have two delegates defined – the NoParamDelegate and OneIntParamDelegate. One takes no parameters. The other takes one integer parameter.

What that means is that the NoParamDelegate can ONLY be assigned to contain the AddressOf a method that takes NO parameters. It cannot hold ANY other pointer to any other method. Given the previous definitions :

// would compile
noParam = AddressOf NoParamMethod
oneParam = AddressOf OneIntParamMethod

// will not compile - you get a type mimatch
noParam = AddressOf OneIntParamMethod
oneParam = AddressOf NoParamMethod

// will not compile 
// although this method has one param the parms do not match types
noParam = AddressOf InvalidOneParmMethod
oneParam = AddressOf InvalidOneParmMethod

Delegates are “fussy” – you MUST assign the addressof a method that has the EXACT SAME SIGNATURE the delegate was defined with.

But once you do this you CAN pass whatever data types you want within your own project.

If you happen to use a delegate to call EXTERNAL code, which is sometimes done in the case of interfacing with system libraries and other non-Xojo code, you often use a Ptr although you can use a delegate as well if you make sure you define the delegate with the signature that matches the external codes (this can be tricky sometimes)

If you do match up the types one thing you will run into is that Xojo objects can not be passed to external code this way. You can only pass ptr’s, structures – careful here as you need to know the specific calling conventions in use – and other simple types. Xojo will coerce many things to the correct type for you just as it does for declares.

EmbeddedWindowControl

If you’ve ever used a container control on a layout and then tried to manipulate the controls at runtime with code like


For i As Integer = 0 To Self.ControlCount - 1
  Dim ctrl As Control = Self.Control(i)  
  // now manipulate this control or call its methods
Next

you’ve probably run into the EmbeddedWindowControl

Its what you get when you use a Container Control on a layout either by placing one at design time or dynamically adding one at runtime.

Note that you get an EmbeddedWindowControl – not an instance of the Container you placed there. So any code you use that tests if a control ISA specific instance will fail for your containers. You don’t get a reference to the instance you get this EmbeddedWindowControl instead. So you cant call any methods you have added to the container control or reference any properties of it.

Its been most annoying. There have been several requests for something to be done so the container the EmbeddedWindowControl was created from can be accessed. Like this one and this one and this one.

And today, for a project I was working on, I needed this and decided to figure out how to make this possible.

The result is this little sample program with one module that extends EmbeddedWindowControl in a way you can get the container control that the embedded window control was created from.

To make use of this simply copy the EmbeddedWindowControlExtensions module into your project. Then when you iterate a set of controls on a layout you can do

For i As Integer = 0 To Self.ControlCount - 1
  
  Dim ctrl As Control = Self.Control(i)
  
  If ctrl IsA EmbeddedWindowControl Then
    
    Dim cc As ContainerControl = EmbeddedWindowControl(ctrl).Container 
    
    If cc <> Nil Then
      // you now have an actual reference to the container control
      // so you can use its methods, properties, etc
      // but you will need to cast it first
    End If
    
  End If
  
Next

Enjoy !

Universal Project : II

In a previous article I detailed some of the things I’d like to see the IDE do to make it so a “Universal Project” that could, from a single source code base, produce one, or more, compiled applications.

The up side to this would be that if you have a suite of related applications the code that is common between them, perhaps business specific logic, would only need to be altered in one place and could immediately be tested across all the related apps much more simply than by using external items, SVN externals, or the Git equivalent.

Currently it’s almost possible to do this on your own in a single project. Except for how the IDE behaves. If you save a Desktop project as a text project you’ll see the project manifest has one set of key value pairs. And if you save a Console project you’ll see there is a lot of commonality but they are not identical. The same is true for a Web and iOS projects. They all share a common set of key value pairs but each type has some that are unique to that type of project.

The downside here is that each project type only reads and saves those key value pairs that it recognizes, and throws away any others. This is easy to test simply by adding your own to any manifest, opening it in the IDE, altering a project setting then saving.

In order to make it so a single project could be a desktop, web, iOS, or console project ALL key value pairs across all these project types would need to be preserved, even if they are not used.

If the IDE did this it would be one step along the path to creating a Universal app.

The Universal project

It’s long been a desire of Xojo users to have a single project thay they can open and compile a desktop app, web app, iOS app and console apps from the same project.

This would make it so if you have a suite of related applications that all use common code sharing that common code would be easier since its all in the same project and just by selecting a different target in the build settings you could compile whichever one you selected.

This would be a really handy capability. One that I’ve used in other IDE’s like Metrowerks CodeWarrior. In there you created a new “Target” and then could designate which “files” were part of the target. Since XOjo isn’t file oriented in that way it would make sense to have some other way to designate which targets a class/module/layout was part of.

In a way this already exists.

If you wrote a module and set its “compatibility” flags either on the whole module you can designate whether that module is compatible with Desktop, Web, iOS, or Console apps. You could create it, save it and then drop it into any one of those kinds of projects and based on those compatibility flag settings it would or would not compile for whatever kind of project you were creating.

Right now the only things that can be selected as compatibility settings are Desktop, Web, iOS, and Console. Either 32 or 64 bits. And when you put a check mark next to one of those items in the Build Settings boolean flags are set (TargetMacOS, TargetWeb, TargetiOS, TargetConsole and either Target32bit or Target64bit)

What if you could add your own targets ? Instead of just desktop, web, ios and console we could create new “Targets”.

When you select “Target” this creates a new spot in the IDE under macOS, Windows, Linux where we could add build steps like we do for macOS, Windows, Linux, Web. And it can be checked or not checked like the other build targets. Then like the others, when checked, a boolean “Target<whatevername we gave it>” should also be crated like happens for macOS, Windows, Linux and others. Then in code we could write

#if TargetUserDefined
#endif

exactly the same as we do with #If TargetMacOS etc.

The other thing we would need is for the compatibility flags editor to have extra rows in it, one for each of the targets we define. That way we could set the proper compatibility settings right in the IDE.

There are still a couple issues that would have to be sorted out in the IDE but this would be one step to making the “Universal Project” that has so long been desired.

If you have interest in this sign on to this case