Tag: CLIControl

The stamping program

To start this year and decennium, I have dug up my old Windows Forms control for command line interfacing with a user in a Windows environment, a control that I still think allows the programmer to accomplish complex interfacing with hardly any coding at all.

This program consist of one form only, and the only added control is the CLI control. The name of the CLI control instance is simply Cli1. I have loaded four images as project resources; a background image and three different colored icons. One is red, one is blue and one is green.

Click on the image to view it in full size.

This is how the program works: Type Red, Green or Blue to select which color you want to “draw” with. Click on an empty space on the CLI control to place a red, green or blue symbol. Click on an existing symbol to remove it. The complete source code for this:

Public Class Form1

    Private Enum Colors
        None
        Red
        Green
        Blue
    End Enum

    Private CurrentColor As Colors = Colors.None

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Cli1.BackgroundImage = My.Resources.Background
        Cli1.WriteLine("Type Red, Green or Blue. Then click!")
    End Sub

    Private Sub Cli1_Click(ByVal Source As Object, _
    ByVal PixelX As Integer, ByVal PixelY As Integer, ByVal CharX As Integer, ByVal CharY As Integer) _
    Handles Cli1.Click
        'What symbol did the user click on?
        Dim S As CLIControl.GraphicalElement = Cli1.GraphicalElements.GetElement(PixelX, PixelY)
        'If any, remove it. Else add a new one.
        If S Is Nothing Then
            'Add a symbol.
            Select Case Me.CurrentColor
                Case Colors.Red
                    Cli1.GraphicalElements.Add(New CLIControl.Picture("", _
                    My.Resources.Circle_Red, PixelX - 16, PixelY - 16))
                Case Colors.Green
                    Cli1.GraphicalElements.Add(New CLIControl.Picture("", _
                    My.Resources.Circle_Green, PixelX - 16, PixelY - 16))
                Case Colors.Blue
                    Cli1.GraphicalElements.Add(New CLIControl.Picture("", _
                    My.Resources.Circle_Blue, PixelX - 16, PixelY - 16))
            End Select
        Else
            'Remove a symbol.
            Cli1.GraphicalElements.Remove(S)
        End If
    End Sub

    Private Sub Cli1_UserTyped(ByVal Source As Object, ByVal Command As String) Handles Cli1.UserTyped
        If Not Command = "" Then
            Select Case Command.ToLower()
                Case "red"
                    Me.CurrentColor = Colors.Red
                Case "green"
                    Me.CurrentColor = Colors.Green
                Case "blue"
                    Me.CurrentColor = Colors.Blue
                Case Else
                    Cli1.WriteLine("Nah!")
            End Select
        End If
    End Sub

End Class

The CLI control can be downloaded from this page, and this program (compiled) is located here.

First CLI control demo

To demonstrate the CLI control, I have made a simple guessing game. The source code is below. If you want to run it yourself, place the exe file and a copy of CLIControl.dll in the same folder.

CLI Control

CLI Control demo

Public Class Form1

	'How many times has the user guessed?
	Private GuessCount As Integer = 0

	'The correct answer (can be 1 to 1000).
	Private CorrectAnswer As Integer

	'A random number generator is needed.
	Private Rnd As New Random()

	'Game flag.
	Private GameOn As Boolean = False

	'At startup, set some properties of the CLI control.
	Private Sub Form1_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load

		'Create a background for the control. If you have a
                'file, use LoadBackgroundFromFile.
		Dim Background As New System.Drawing.Bitmap(20, 50)
		Using G As System.Drawing.Graphics = Graphics.FromImage(Background)
			Using Blue1 As New SolidBrush(Color.FromArgb(255, 20, 40, 60))
				G.FillRectangle(Blue1, 0, 0, 20, 50)
			End Using
			Using Blue2 As New SolidBrush(Color.FromArgb(255, 40, 60, 80))
				G.FillRectangle(Blue2, 0, 10, 20, 10)
			End Using
		End Using
		'Assign the background (not needed if you use LoadBackgroundFromFile).
		Cli1.BackgroundImage = Background

		'Create and assing a brush for the text font.
		Cli1.TextBrush = New System.Drawing.Drawing2D.LinearGradientBrush( _
		 New Point(0, 0), _
		 New Point(0, Cli1.Height), _
		 Color.FromArgb(100, 255, 255, 255), _
		 Color.FromArgb(255, 255, 255, 255))

		'Add a shadow to the text.
		Cli1.TextShadow = True

		'The number that the user is trying to find (1 to 1000).
		Me.CorrectAnswer = Me.Rnd.Next(1, 1001)

		'Say something to the user, and add some lines for decoration.
		Cli1.WriteLine("Welcome! Guess a number between 1 and 1000!")
		Cli1.WriteLine()
		Dim P As New System.Drawing.Pen(Color.Yellow, 2)
		Cli1.GraphicalElements.AddLine("", P, 0, 304, Cli1.Width, 0)
		Cli1.GraphicalElements.AddLine("", P, 0, 323, Cli1.Width, 0)

		'Go!
		Me.GameOn = True
	End Sub

	Private Sub Cli1_UserTyped(ByVal Sender As Object, _
        ByVal Command As String) Handles Cli1.UserTyped
		'If the game is running, assume that the user is guessing
                'on the correct number.
		If GameOn Then
			Try
				Dim I As Integer = Integer.Parse(Command)
				If I < 1 Or I > 1000 Then
					Cli1.WriteLine("The number must be between 1 and 1000!")
				Else

					'Increase the number of guesses.
					Me.GuessCount += 1

					'Display the guess count as an image.
					Me.AddGuessCountImage()

					If I = CorrectAnswer Then

						'Correct!
						Cli1.WriteLine("Correct in " & Me.GuessCount.ToString() & _
                                                        " guesses!")
						Cli1.WriteLine()
						'Add a green line.
						Cli1.GraphicalElements.AddLine("", Pens.Green, 0, _
                                                         323, Cli1.Width, 0)
						Me.GameOn = False

					ElseIf I < CorrectAnswer Then

						Cli1.WriteLine("I am thinking of a larger number.")

					ElseIf I > CorrectAnswer Then

						Cli1.WriteLine("I am thinking of a smaller number.")

					End If

				End If
			Catch ex As Exception
				Cli1.WriteLine("You must type a number between 1 and 1000!")
			End Try
		Else
			Console.WriteLine("Game over!")
		End If
	End Sub

	Private Sub AddGuessCountImage()
		Dim B As New System.Drawing.Bitmap(70, 70)
		Using F As New System.Drawing.Font("Times New Roman", 30, FontStyle.Regular)
			Dim GuessCountString As String = Me.GuessCount.ToString()
			Using G As Graphics = Graphics.FromImage(B)
				G.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
				G.FillEllipse(Brushes.Black, 0, 0, 69, 69)
				G.DrawEllipse(Pens.Red, 0, 0, 69, 69)
				Dim StringSize As SizeF = G.MeasureString(GuessCountString, F)
				Dim X As Single = 35 - (StringSize.Width / 2)
				Dim Y As Single = 35 - (StringSize.Height / 2)
				G.DrawString(GuessCountString, F, Brushes.White, X, Y)
			End Using
		End Using
		Cli1.GraphicalElements.AddPicture("", B, 400 + Me.Rnd.Next(200), 250)
	End Sub

End Class

Vector graphics in CLI control

This post is done from the middle of nowhere and I am using my 3G phone as a modem. I hope that I manage to upload everything.

I have added support for vector graphics in my CLI control to make the control more versatile. A collection named GraphicalElement holds the graphics to be drawn. Graphical elements in the collection can be manipulated and changes are reflected when the control is redrawn (you can call the Invalidate method to flag the control as dirty). When scrolling occurs, all graphical elements also are moved up. Elements are deleted when they scroll out of view.

This simple example shows how to add graphics (it draws 60 bars in a nice pattern):

For I As Integer = 1 To 60
Cli1.GraphicalElements.AddBox(“”, Brushes.Yellow, I * 10, 10, 8, _
CType(50 + (Math.Sin(I / 3) * 50), Integer))
Next

Because elements are deleted automatically when they scroll out of view, items will get new index numbers. Therefore, you should either save a reference to the item (a reference can be created manually using the Box constructor, but a reference to a Box is also given as return value from the AddBox method) or give the element a name, and then acquire a reference when a reference is needed using the FindElementByName method of the GraphicalElement collection.

When I have the opportunity, I will do some more examples and some illustrations.