Startsidan  ▸  Texter  ▸  Teknikblogg

Anders Hesselbom

Programmerare, skeptiker, sekulärhumanist, antirasist.
Författare till bok om C64 och senbliven lantis.
Röstar pirat.

Console controls, the concept

2009-06-18

To illustrate what I was talking about here, I made a simple list box to show the concept. The picture illustrates what it looks like, and the code follows.

The Module1 module is the console application with the Main method (startup).

The ConsoleControl class is an abstract base for console controls. This class is for now incredible trivial, and I just built it to make this point.

Then, the ListBox class is the “control” itself and the ListBox item is a pair of a Long (the value) and a String (the visible representation).

I might be way out here, but I’d love to have something like this.

Module Module1

    Sub Main()

		'Create a listbox.
		Dim Lb As New ListBox()

		'Set some properties.
		Lb.Height = 4

		'Add some items
		Lb.Add(4, "One")
		Lb.Add(542, "Two")
		Lb.Add(9, "Three")
		Lb.Add(10, "Four")
		Lb.Add(11, "Five")
		Lb.Add(12, "Six")
		Lb.Add(13, "Seven")

		'Let the user make a selection.
		Dim Answer As Integer = Lb.Ask()

		'Just for testing: Pause to make sure that the console window is restored.
		Console.ReadLine()

		'Write out the answer and pause again.
		Console.WriteLine(Answer.ToString())
		Console.ReadLine()

    End Sub

End Module

Public MustInherit Class ConsoleControl

	Private m_X As Integer
	Private m_Y As Integer
	Private mWidth As Integer
	Private mHeight As Integer

	Private mBackgroundColor As System.ConsoleColor
	Private mForegroundColor As System.ConsoleColor
	Private mHighlightedBackgroundColor As System.ConsoleColor
	Private mHighlightedForegroundColor As System.ConsoleColor
	Private mInactiveForegroundColor As System.ConsoleColor

	Public Sub New()
		Me.m_X = 1
		Me.m_Y = 1
		Me.mWidth = 20
		Me.mHeight = 10
		Me.mBackgroundColor = ConsoleColor.Blue
		Me.mForegroundColor = ConsoleColor.White
		Me.mHighlightedBackgroundColor = ConsoleColor.White
		Me.mHighlightedForegroundColor = ConsoleColor.Blue
		Me.mInactiveForegroundColor = ConsoleColor.Gray
	End Sub

	Public Property X() As Integer
		Get
			Return Me.m_X
		End Get
		Set(ByVal value As Integer)
			Me.m_X = value
		End Set
	End Property

	Public Property Y() As Integer
		Get
			Return Me.m_Y
		End Get
		Set(ByVal value As Integer)
			Me.m_Y = value
		End Set
	End Property

	Public Property Width() As Integer
		Get
			Return Me.mWidth
		End Get
		Set(ByVal value As Integer)
			Me.mWidth = value
		End Set
	End Property

	Public Property Height() As Integer
		Get
			Return Me.mHeight
		End Get
		Set(ByVal value As Integer)
			Me.mHeight = value
		End Set
	End Property

	Public Property BackgroundColor() As ConsoleColor
		Get
			Return Me.mBackgroundColor
		End Get
		Set(ByVal value As ConsoleColor)
			Me.mBackgroundColor = value
		End Set
	End Property

	Public Property ForegroundColor() As ConsoleColor
		Get
			Return Me.mForegroundColor
		End Get
		Set(ByVal value As ConsoleColor)
			Me.mForegroundColor = value
		End Set
	End Property

	Public Property HighlightedBackgroundColor() As ConsoleColor
		Get
			Return Me.mHighlightedBackgroundColor
		End Get
		Set(ByVal value As ConsoleColor)
			Me.mHighlightedBackgroundColor = value
		End Set
	End Property

	Public Property HighlightedForegroundColor() As ConsoleColor
		Get
			Return Me.mHighlightedForegroundColor
		End Get
		Set(ByVal value As ConsoleColor)
			Me.mHighlightedForegroundColor = value
		End Set
	End Property

	Public Property InactiveForegroundColor() As ConsoleColor
		Get
			Return Me.mInactiveForegroundColor
		End Get
		Set(ByVal value As ConsoleColor)
			Me.mInactiveForegroundColor = value
		End Set
	End Property

End Class


Public Class ListBox
	Inherits ConsoleControl

	Private mItems As List(Of ListBoxItem)
	Private mViewOffset As Integer
	Private mSelectedIndex As Integer
	Private mSpacer As String = Nothing

	Public Sub New()
		MyBase.New()
		Me.mItems = New List(Of ListBoxItem)()
		Me.mSelectedIndex = -1
		Me.mViewOffset = 0
	End Sub

	Friend ReadOnly Property Items() As List(Of ListBoxItem)
		Get
			Return Me.mItems
		End Get
	End Property

	Public Function Add(ByVal Value As Integer, ByVal DisplayText As String) As Integer
		Dim Item As New ListBoxItem(Me, Value, DisplayText)
		Item.Index = mItems.Count
		mItems.Add(Item)
		Return Item.Index
	End Function

	Public Property SelectedIndex() As Integer
		Get
			Return Me.mSelectedIndex
		End Get
		Friend Set(ByVal value As Integer)
			Me.mSelectedIndex = value
		End Set
	End Property

	Public Function Ask() As Integer
		Return Me.Ask(0)
	End Function

	Public Function Ask(ByVal DefaultValue As Integer) As Integer
		If Me.mItems.Count > 0 Then

			Me.mSpacer = Space(Me.Width)

			Dim CursorVisible As Boolean = Console.CursorVisible
			Dim FG As ConsoleColor = Console.ForegroundColor
			Dim BG As ConsoleColor = Console.BackgroundColor
			Console.CursorVisible = False

			Me.SelectedIndex = ValueToIndex(DefaultValue)
			Do
				Me.DrawRegular()
				Dim Key As ConsoleKeyInfo = Console.ReadKey(True)
				If Key.Key = ConsoleKey.Escape Then
					Me.SelectedIndex = -1
					Exit Do
				ElseIf Key.Key = ConsoleKey.Enter Then
					Exit Do
				Else
					Select Case Key.Key
						Case ConsoleKey.UpArrow
							If Me.SelectedIndex = 0 Then
								Me.SelectedIndex = Me.mItems.Count - 1
							Else
								Me.SelectedIndex -= 1
							End If
						Case ConsoleKey.DownArrow
							If Me.SelectedIndex < (Me.mItems.Count - 1) Then
								Me.SelectedIndex += 1
							Else
								Me.SelectedIndex = 0
							End If
					End Select
				End If
			Loop
			Me.DrawDead()

			Console.CursorVisible = CursorVisible
			Console.ForegroundColor = FG
			Console.BackgroundColor = BG
			Dim CursY As Integer = (Me.Y + Me.Height)
			If CursY >= Console.WindowHeight Then
				CursY = Console.WindowHeight - 1
			End If
			Console.CursorTop = CursY
			Console.CursorLeft = 0
			Return Me.mItems(Me.SelectedIndex).Value
		Else
			Return -1
		End If
	End Function

	Private Function ValueToIndex(ByVal Value As Integer) As Integer
		'This is only called from the Ask function, and the Ask funktion will only run if mItems.Count>0. No need for extra check.
		For I As Integer = 0 To Me.mItems.Count - 1
			If Me.mItems(I).Value = Value Then
				Return I
			End If
		Next
		Return 0
	End Function

	Private Sub DrawRegular()
		'Make sure that the selection is inside the visible area.
		If Me.mViewOffset > Me.SelectedIndex Then
			While Me.mViewOffset > Me.SelectedIndex
				Me.mViewOffset -= 1
			End While
		ElseIf (Me.mViewOffset + Me.Height) <= Me.SelectedIndex Then
			While (Me.mViewOffset + Me.Height) <= Me.SelectedIndex
				Me.mViewOffset += 1
			End While
		End If

		'Draw the visible items.
		For I As Integer = 0 To Me.Height - 1
			Dim IndexToDisplay As Integer = I + Me.mViewOffset
			Console.CursorLeft = Me.X
			Console.CursorTop = Me.Y + I
			If IndexToDisplay < Me.mItems.Count Then

				If Me.mItems(IndexToDisplay).Selected Then
					Console.ForegroundColor = Me.HighlightedForegroundColor
					Console.BackgroundColor = Me.HighlightedBackgroundColor
				Else
					Console.ForegroundColor = Me.InactiveForegroundColor
					Console.BackgroundColor = Me.BackgroundColor
				End If

				Console.Write(Me.mItems(IndexToDisplay).DisplayString)
			Else
				Console.ForegroundColor = Me.InactiveForegroundColor
				Console.BackgroundColor = Me.BackgroundColor
				Console.Write(Me.mSpacer)
			End If
		Next
	End Sub

	Private Sub DrawDead()
		'Draw the visible items as inactive.
		For I As Integer = 0 To Me.Height - 1
			Dim IndexToDisplay As Integer = I + Me.mViewOffset
			Console.CursorLeft = Me.X
			Console.CursorTop = Me.Y + I
			If IndexToDisplay < Me.mItems.Count Then

				If Me.mItems(IndexToDisplay).Selected Then
					Console.ForegroundColor = Me.ForegroundColor
					Console.BackgroundColor = Me.BackgroundColor
				Else
					Console.ForegroundColor = Me.InactiveForegroundColor
					Console.BackgroundColor = Me.BackgroundColor
				End If

				Console.Write(Me.mItems(IndexToDisplay).DisplayString)
			Else
				Console.ForegroundColor = Me.InactiveForegroundColor
				Console.BackgroundColor = Me.BackgroundColor
				Console.Write(Me.mSpacer)
			End If
		Next
	End Sub

End Class

Friend Class ListBoxItem

	Private mListBox As ListBox
	Private mValue As Integer
	Private mText As String

	Private mIndex As Integer = 0
	Private mDisplayString As String = Nothing

	Friend Sub New(ByVal Owner As ListBox, ByVal Value As Integer, ByVal DisplayText As String)
		Me.mListBox = Owner
		Me.mValue = Value
		Me.mText = DisplayText.Trim()
	End Sub

	Public Property Index() As Integer
		Get
			Return Me.mIndex
		End Get
		Friend Set(ByVal value As Integer)
			Me.mIndex = value
		End Set
	End Property

	Friend ReadOnly Property OwnerListBox() As ListBox
		Get
			Return Me.mListBox
		End Get
	End Property

	Public ReadOnly Property Value() As Integer
		Get
			Return Me.mValue
		End Get
	End Property

	Public ReadOnly Property Text() As String
		Get
			Return Me.mText
		End Get
	End Property

	Public Property Selected() As Boolean
		Get
			Return (Me.OwnerListBox.SelectedIndex = Me.Index)
		End Get
		Set(ByVal value As Boolean)
			If value Then
				Me.OwnerListBox.SelectedIndex = Me.Index
			Else
				Me.OwnerListBox.SelectedIndex = -1
			End If
		End Set
	End Property

	Friend ReadOnly Property DisplayString() As String
		Get
			If Me.mDisplayString Is Nothing Then
				'This code will only run once per item, but it still needs rewriting. Risk for multiple memory reallocations.
				Me.mDisplayString = " " & Me.Text
				If Me.mDisplayString.Length > Me.OwnerListBox.Width Then
					Me.mDisplayString = Me.mDisplayString.Substring(0, Me.OwnerListBox.Width)
				Else
					While Me.mDisplayString.Length < Me.OwnerListBox.Width
						Me.mDisplayString &= " "
					End While
				End If
			End If
			Return Me.mDisplayString
		End Get
	End Property

End Class

Categories: Microsoft .NET

Leave a Reply

Your email address will not be published. Required fields are marked *



En kopp kaffe!

Bjud mig på en kopp kaffe (20:-) som tack för bra innehåll!

Bjud på en kopp kaffe!

Om...

Kontaktuppgifter, med mera, finns här.

Följ mig

Twitter Instagram
GitHub RSS

Public Service

Folkbildning om public service.

Hem   |   linktr.ee/hesselbom   |   winsoft.se   |   80tal.se   |   Filmtips