This project shows you to how to build HMI screens quickly and easily with MicroLayout, a new lightweight GUI library for embedded devices. We'll go over the different controls it currently supports, and its styling capabilities so you can build highly customizable screens. We'll use a Project Lab v3's for its 2.3 inch screen and push buttons to control an interactive menu as an example.
Project Lab is the most functional IoT prototyping platform on the planet. No more breadboards, complicated wiring, or soldering. Project Lab was built from the ground up using the industry's most powerful, capable, and reliable sensors, components, and connectors.
Before you dive in this project, ensure that your Meadow board and development environment is fully up to date. Check the Release Notes section to double check.
Step 2 - Create a Meadow Application projectCreate a new Meadow Application project in Visual Studio 2022 for Windows or macOS and name it MicroLayoutMenu.
Step 3 - Add the required NuGet packagesFor this project, search and install the following NuGet packages:
Step 4 - Write the demo screen for MicroLayoutMenuDownload this Meadow bitmap image and add it to your project, setting its build action to Embedded Resource.
MeadowApp class
Replace your MeadowApp class with the snippet below:
public class MeadowApp : App<F7CoreComputeV2>
{
private IProjectLabHardware _projectLab;
private DisplayScreen _screen;
public override Task Initialize()
{
_projectLab = ProjectLab.Create();
_screen = new DisplayScreen(_projectLab.Display, RotationType._270Degrees);
return base.Initialize();
}
void ShowDemoScreen()
{
var image = Image.LoadFromResource("MicroLayoutMenu.img_meadow.bmp");
_screen.Controls.Add(
new DisplayBox(0, 0, _screen.Width, _screen.Height)
{
ForeColor = Color.White
},
new DisplayLabel(15, 20, 290, 40)
{
Text = "Welcome to MicroLayout!",
TextColor = Color.Black,
BackColor = Color.FromHex("#C9DB31"),
Font = new Font12x20(),
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
},
new DisplayImage(90, 74, 140, 90, image)
{
BackColor = Color.FromHex("#23ABE3"),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
},
new DisplayButton(30, 178, 120, 40)
{
Text = "Button 1",
TextColor = Color.Black,
Font = new Font12x20(),
},
new DisplayButton(170, 178, 120, 40)
{
Text = "Button 2",
TextColor = Color.White,
ForeColor = Color.Red,
ShadowColor = Color.FromHex("#555555"),
Font = new Font12x20(),
});
}
public override Task Run()
{
ShowDemoScreen();
return base.Run();
}
}
- In the
Initialize
method, we instantiate aDisplayScreen
, a page container that stores a list of controls. - in
ShowDemoScreen
, notice we reference theDisplayScreen
object to access itsControls
list, and we start adding MicroLayout controls like Labels, Images, Box panel and an Image. For each element, notice you must always pass its x and y coordinates (referencing top left corner), and its width and height dimensions.
When you run the project, you should see the following screen
As shown above, lets go over the different controls MicroLayout currently supports
- DisplayBox - a rectangle that you can specify its color, visibility and filled or just outline.
- DisplayLabel - a control that draws text in a single line. You can specify font size, text color, vertical and horizontal alignment, background color, and font scaling.
- DisplayImage - a control to easily draw bitmap images. If the provided width and height are greater than the image it self, it will be remain centered, and you can specify a background color that will be applied outside of the image boundaries.
- DisplayButton - an onscreen button, only interactive for touch screen displays. You can customize its text color, font size, shadow color, forecolor, color when pressed, and highlight color when selected.
Menuclass
Add a new class named Menu
and copy the following:
public class Menu
{
private DisplayLabel[] _labels;
private DisplayBox _highlightBox;
private const int ItemHeight = 30;
public int SelectedRow { get; set; } = 0;
public readonly Color UnselectedTextColor = Color.AntiqueWhite;
public readonly Color SelectedTextColor = Color.Black;
public readonly Color SelectionColor = Color.Orange;
public readonly IFont MenuFont = new Font12x20();
public Menu(string[] items, DisplayScreen screen)
{
_labels = new DisplayLabel[items.Length];
var x = 2;
var y = 0;
var height = ItemHeight;
// we compose the screen from the back forward, so put the box on first
_highlightBox = new DisplayBox(0, -1, screen.Width, ItemHeight + 2)
{
ForeColor = SelectionColor,
Filled = true,
};
screen.Controls.Add(_highlightBox);
for (var i = 0; i < items.Length; i++)
{
_labels[i] = new DisplayLabel(
left: x,
top: i * height,
width: screen.Width,
height: height)
{
Text = items[i],
Font = MenuFont,
BackColor = Color.Transparent,
VerticalAlignment = VerticalAlignment.Center,
};
// select the first item
if (i == 0)
{
_labels[i].TextColor = SelectedTextColor;
}
else
{
_labels[i].TextColor = UnselectedTextColor;
}
screen.Controls.Add(_labels[i]);
y += height;
}
}
public void Down()
{
if (SelectedRow < _labels.Length - 1)
{
SelectedRow++;
Resolver.Log.Info($"MENU SELECTED: {_labels[SelectedRow].Text}");
Draw(SelectedRow - 1, SelectedRow);
}
}
public void Up()
{
if (SelectedRow > 0)
{
SelectedRow--;
Resolver.Log.Info($"MENU SELECTED: {_labels[SelectedRow].Text}");
Draw(SelectedRow + 1, SelectedRow);
}
}
public void Draw(int oldRow, int newRow)
{
_labels[oldRow].TextColor = UnselectedTextColor;
_labels[newRow].TextColor = SelectedTextColor;
_highlightBox.Top = _labels[newRow].Top - 1;
}
}
- In the
Menu
Constructor, it receives a list of string items, highlighting the first item by default (using aDisplayBox
), and then iterates over the rest as not selected items. - The
Up
andDown
methods will switch the next or previous item to show it as selected. - The
Draw
method changes the selected item'sTextColor
, and its predecessor back to not selected, and moves the highlight box to the selected Item by setting itsTop
property.
MeadowApp class
Replace the contents of Meadow App class with:
public class MeadowApp : App<F7CoreComputeV2>
{
private IProjectLabHardware _projectLab;
private DisplayScreen _screen;
public override Task Initialize()
{
_projectLab = ProjectLab.Create();
_screen = new DisplayScreen(_projectLab.Display, RotationType._270Degrees);
return base.Initialize();
}
void ShowMenuScreen()
{
var menuItems = new string[]
{
"Item A",
"Item B",
"Item C",
"Item D",
"Item E",
"Item F",
};
var menu = new Menu(menuItems, _screen);
_projectLab.UpButton.Clicked += (s, e) => menu.Up();
_projectLab.DownButton.Clicked += (s, e) => menu.Down();
}
public override Task Run()
{
ShowMenuScreen();
return base.Run();
}
}
- In the
Initialize
method, we instantiate aDisplayScreen
, a page container that stores a list of controls. - In
ShowMenuScreen
, we create an array of strings with all the menu items, and are passed to the Menu's constructor along with the Project Lab's screen, which will draw the menu with the first item selected. - Finally, we register the
Clicked
event to Project Labs's up and down push buttons to select the next and previous items on the menu,
Click the Run button in Visual Studio. It should look like to the following GIF:
This project is only the tip of the iceberg in terms of the extensive exciting things you can do with Meadow.Foundation.
- It comes with a huge peripheral driver library with drivers for the most common sensors and peripherals.
- The peripheral drivers encapsulate the core logic and expose a simple, clean, modern API.
- This project is backed by a growing community that is constantly working on building cool connected things and are always excited to help new-comers and discuss new projects.
Comments
Please log in or sign up to comment.