-
-
Notifications
You must be signed in to change notification settings - Fork 10
first widgets2
Berfor choosing the right base class for your new control, you have to answer two questions:
- Will my control accept children?
- do I need it to be templated?
The following graph will guide you to the right ancestor for your needs:
For the purpose of this example, let's create a simple gauge that will display an integer value as a vertical bar between 0 and a maximum value.
You are free to choose your namespace, crow will search the control among all exported types of the entry assembly, and the IML language don't check namespaces.
using System;
using Crow;
namespace Tests
{
public class SimpleGauge : Widget
{
public SimpleGauge (){}
public SimpleGauge (Interface iface): base (iface){}
}
}
We implement here the constructor accepting the interface as argument to be able to create this control from the c# source. If no constructor is provided, the compiler will create the default parameterless one that will allow us to instantiate the control from IML. But if you choose to implement the interface constructor, you must implement also the parameterless one that will not be created automatically by the compiler in that case.
For simplicity, lets start with a simple gauge between fixed bounds (from 0 to 100), and let's create a Level property.
int level;
public int Level
{
get { return level; }
set {
if (level == value)
return;
level = value;
NotifyValueChanged ("Level", level);
}
}
There are three steps in the setting of a Crow property:
- First, we have to test against the actual value (
level==value
), this is mandatory for the binding system to work property in the case of a two way binding. - Next, we handle what to do with the value, here we store it in a local variable.
- Finaly, we have to notify Crow of the value change with
NotifyValueChanged
. It is a helper function defined in Widget to trigger the ValueChanged events. The property name passed in parameter is case sensitive.
Now, let's draw our level on screen, for this, we override the onDraw
method of Widget:
protected override void onDraw (Context gr)
{
base.onDraw (gr);
This function has the current drawing backend context as argument, for now the only 2d vector library supported is Cairo. Add also the using directive on top: using Cairo;
To draw something, we first need to know the bounds of the available surface, the ClientRectangle
property of the ILayoutable interface implemented in the base class has it in the local coordinate system of our widget, taking care of the margin defined.
Rectangle bounds = ClientRectangle;
We will draw the Level vertically from bottom to top, so we devide the available height by the maximum, and we multiply by our value, we also have to increment the rectangle y value by the void on top of the gauge.
int gaugeHeight = r.Height / 100 * level;
r.Y += r.Height - gaugeHeight;
r.Height = gaugeHeight;
Foreground.SetAsSource (gr);
gr.Rectangle (r);
gr.Fill ();
Foreground
type is Fill
, it is not used by default in the base class, so we may use it as the source color for our gauge. The Fill
class offers a helper method to set it as the source of drawing operation. Once the source color set, we call the Rectangle command, and then tell the backend what to do with it by calling its Fill method.
That's it, you have a brand new graphical object ready for production, so let's instantiate one, you may reuse your first application and in the onLoad
override, create a gauge:
protected override void OnLoad (EventArgs e)
{
base.OnLoad (e);
AddWidget (new SimpleGauge (CurrentInterface)
{
Level = 40,
Width = 30, Height = "50%",
Foreground = Color.UnitedNationsBlue,
Background = Color.Jet
});
}
You may also instantiate a new gauge with IML either by loading if from an xml file, or by passing directely an valid IML string to the LoadIMLFragment
helper function from the CrowWindow:
LoadIMLFragment (@"<SimpleGauge Level='40' Margin='5' Background='Jet' Foreground='Gray' Width='30' Height='50%'/>");
A valid minimal IML file could be:
<SimpleGauge Level='40' Margin='5' Background='Jet' Foreground='Gray' Width='30' Height='50%'/>