Skip to content

Instantly share code, notes, and snippets.

@mikz
Created May 4, 2011 06:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikz/954821 to your computer and use it in GitHub Desktop.
Save mikz/954821 to your computer and use it in GitHub Desktop.
Imports Calculator.CalculatorModel
Public Class Calculator
Dim WithEvents model As CalculatorModel
Private Sub MemoryController(ByVal sender As System.Windows.Forms.Button, ByVal e As System.EventArgs) Handles MemCBtn.Click, MemMBtn.Click, MemPBtn.Click, MemRBtn.Click, MemSBtn.Click
Try
model.CallMemory(sender.Text)
Catch ex As CalculationException
HandleCalculationException(ex)
End Try
End Sub
Private Sub OperatorController(ByVal sender As System.Windows.Forms.Button, ByVal e As System.EventArgs) Handles OpAdtnBtn.Click, OpDivBtn.Click, OpMtplBtn.Click, OpSubsBtn.Click
Try
model.PutOperator(sender.Text.Chars(0))
Catch ex As CalculationException
HandleCalculationException(ex)
End Try
End Sub
Private Sub FunctionController(ByVal sender As System.Windows.Forms.Button, ByVal e As System.EventArgs) Handles btnAns.Click, FncBackBtn.Click, FncCBtn.Click, FncCEBtn.Click, FncInvBtn.Click, FncPerctBtn.Click, FncPlMnBtn.Click, FncSqrtBtn.Click
Try
model.CallFunction(sender.Text)
Catch ex As CalculationException
HandleCalculationException(ex)
End Try
End Sub
Private Sub NumberController(ByVal sender As System.Windows.Forms.Button, ByVal e As System.EventArgs) Handles Num0Btn.Click, Num1Btn.Click, Num2Btn.Click, Num3Btn.Click, Num4Btn.Click, Num5Btn.Click, Num6Btn.Click, Num7Btn.Click, Num8Btn.Click, Num9Btn.Click, OpDelimBtn.Click
If model.currentValue.ToString().Length < 15 Or model.fin Then
model.PutNumber(sender.Text.Chars(0))
End If
End Sub
Private Sub RefreshLog()
lblLog.Text = ""
If model.log.Count >= 1 Then
lblLog.Text = String.Join(" ", model.log.GetRange(0, model.log.Count).ToArray)
If lblLog.Text.Length > 25 Then
lblLog.Text = "«" + lblLog.Text.Substring(lblLog.Text.Length - 24, 24)
End If
End If
End Sub
Private Sub model_MemoryChange(ByVal MemoryValue As Double) Handles model.MemoryChange
If MemoryValue = 0 Then
lblMemory.Text = ""
Else
lblMemory.Text = "M"
End If
End Sub
Private Sub RefreshAns() Handles model.UpdatedLog
RefreshLog()
If model.currentValue.ToString().ToLower().IndexOf("e") > 0 Then
LogResult(model.currentValue.ToString("0.0#########e+#0"))
Else
LogResult(model.currentValue.ToString())
End If
End Sub
Private Sub HandleCalculationException(ByVal ex As CalculationException)
RefreshLog()
LogResult(ex.Message)
End Sub
Private Sub LogResult(ByVal str As String)
If model.lastOpDecimal Then
str &= ","
End If
If model.Fraction.HasValue And model.Fractions > 0 And (currentValue - Math.Round(model.currentValue, 0)) <> 0 Then
For i = 0 To model.Fractions
str &= "0"
Next i
End If
lblCurNumber.Text = str
If lblCurNumber.Text.Length > 12 Then
lblCurNumber.Font = New Font("Consolas", 12)
Else
lblCurNumber.Font = New Font("Consolas", 18)
End If
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
model = New CalculatorModel
RefreshAns()
End Sub
Private Sub Calculator_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
If "0123456789".Contains(e.KeyChar) Then
model.PutNumber(Val(e.KeyChar))
e.Handled = True
'ElseIf ",".Contains(e.KeyChar) Then
' model.PutNumber(CChar(","))
' e.Handled = True
ElseIf "+-*/".Contains(e.KeyChar) Then
model.PutOperator(e.KeyChar)
e.Handled = True
ElseIf "=".Contains(e.KeyChar) Then
model.CallFunction(e.KeyChar)
e.Handled = True
ElseIf e.KeyChar = ChrW(Keys.Enter) Then
model.CallFunction(FunctionEnum.Ans)
e.Handled = True
End If
End Sub
Private Sub KopírovatToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles KopírovatToolStripMenuItem.Click
Clipboard.SetText(lblCurNumber.Text)
End Sub
Private Sub VložitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles VložitToolStripMenuItem.Click
If Clipboard.GetText().Length > 0 Then
model.ClearEntry()
For i As Integer = 0 To Clipboard.GetText().Length - 1
Dim ch As Char = Clipboard.GetText().Chars(i)
If Char.IsDigit(ch) Or ch = "," Then
model.PutNumber(ch)
End If
Next
End If
End Sub
End Class
Class CalculatorModel
Dim LogArray As ArrayList = New ArrayList()
Dim LeftSideValue As Nullable(Of Double) = Nothing
Dim RightSideValue As Nullable(Of Double) = 0
Dim LastRightSideValue As Nullable(Of Double) = Nothing
Dim MemoryValue As Nullable(Of Double) = 0
Dim Fraction As Nullable(Of Double) = Nothing
Dim Finished As Boolean = False
Dim Op, LastOp As Nullable(Of OperatorEnum)
Dim LastOpDeci As Boolean
Public Event UpdatedLog()
Public Event MemoryChange(ByVal MemoryValue As Double)
Public Class CalculationException
Inherits Exception
Public Sub New(ByVal message As String)
MyBase.New(message)
End Sub
End Class
Public Enum OperatorEnum
Subtraction
Addition
Multiplication
Division
End Enum
Public Enum MemoryEnum
Clear
Recall
Store
Add
Subtract
End Enum
Public Enum FunctionEnum
Ans
Clear
ClearEntry
PlusMinus
Back
Percent
Invert
Sqrt
End Enum
Public ReadOnly Property Fractions() As Integer
Get
Return CStr(Fraction).Length - 1
End Get
End Property
Public ReadOnly Property fin As Boolean
Get
Return Finished
End Get
End Property
Public ReadOnly Property lastOpDecimal As Boolean
Get
Return LastOpDeci
End Get
End Property
Public ReadOnly Property log As ArrayList
Get
Return LogArray
End Get
End Property
Public ReadOnly Property rightSide() As Nullable(Of Double)
Get
Return RightSideValue
End Get
End Property
Public ReadOnly Property leftSide() As Nullable(Of Double)
Get
Return LeftSideValue
End Get
End Property
Sub New()
Debug.Print("CalculatorModel New()")
End Sub
Sub Clear()
log.Clear()
LastOp = Nothing
LastRightSideValue = Nothing
ClearEntry()
End Sub
Sub ClearEntry()
RightSideValue = 0
Finished = False
Fraction = Nothing
End Sub
Private Sub ResetNumber()
If Not rightSide.HasValue Or Finished Then
RightSideValue = 0
Finished = False
Fraction = Nothing
End If
End Sub
Sub PutNumber(ByVal num As Char)
LastOpDeci = False
Dim number As Integer
If Integer.TryParse(num, number) Then
PutNumber(number)
ElseIf num = "," And (Not Fraction.HasValue Or Finished) Then
ResetNumber()
Fraction = 10
LastOpDeci = True
RaiseEvent UpdatedLog()
End If
End Sub
Sub PutNumber(ByVal number As Integer)
ResetNumber()
If Fraction.HasValue Then
RightSideValue += number / Fraction
Fraction *= 10
Else
RightSideValue *= 10
RightSideValue += number
End If
RaiseEvent UpdatedLog()
End Sub
Sub PutOperator(ByVal oper As String)
LastOpDeci = False
Select Case oper
Case "-"
PutOperator(OperatorEnum.Subtraction)
Case "+"
PutOperator(OperatorEnum.Addition)
Case "/"
PutOperator(OperatorEnum.Division)
Case "*"
PutOperator(OperatorEnum.Multiplication)
Case Else
Throw New ApplicationException("Unknown operator " + oper)
End Select
End Sub
Sub PutOperator(ByVal oper As OperatorEnum)
If Not Op Is Nothing Then 'If operator was alredy set
If Not IsNothing(rightSide) Then 'And if we have both sides of equation
log.Add(rightSide)
log.Add(OperatorString(oper))
LeftSideValue = Count() 'Count Left side
RightSideValue = Nothing 'Reset right side
Finished = True
'ElseIf log.Item(log.Count - 1).GetType.Name = "OperatorEnum" Then
Else
log.Item(log.Count - 1) = OperatorString(oper)
End If
Else 'We have only one operator, no counting required
If IsNothing(leftSide) Then 'And there is empty left side
log.Add(rightSide)
log.Add(OperatorString(oper))
LeftSideValue = RightSideValue 'Assign right side to left
RightSideValue = Nothing 'And reset right side
Finished = True
End If
End If
Op = oper 'And assign new operator
RaiseEvent UpdatedLog()
End Sub
Sub CallMemory(ByVal memory As String)
LastOpDeci = False
If memory.Length = 2 Then
memory = memory.Chars(1)
End If
Select Case memory
Case "C"
CallMemory(MemoryEnum.Clear)
Case "R"
CallMemory(MemoryEnum.Recall)
Case "S"
CallMemory(MemoryEnum.Store)
Case "+"
CallMemory(MemoryEnum.Add)
Case "-"
CallMemory(MemoryEnum.Subtract)
Case Else
Throw New ApplicationException("Unknown memory function M" + memory)
End Select
End Sub
Sub CallMemory(ByVal memory As MemoryEnum)
Select Case memory
Case MemoryEnum.Clear
MemoryValue = 0
Case MemoryEnum.Store
MemoryValue = RightSideValue
Case MemoryEnum.Recall
RightSideValue = MemoryValue
Case MemoryEnum.Add
MemoryValue += RightSideValue
Case MemoryEnum.Subtract
MemoryValue -= RightSideValue
Case Else
Throw New ApplicationException("Unknown memory function " + memory)
End Select
RaiseEvent MemoryChange(MemoryValue)
Finished = True 'Start typing new number after using Memory functions
RaiseEvent UpdatedLog()
End Sub
Sub CallFunction(ByVal func As String)
LastOpDeci = False
Select Case func
Case "="
CallFunction(FunctionEnum.Ans)
Case "C"
CallFunction(FunctionEnum.Clear)
Case "CE"
CallFunction(FunctionEnum.ClearEntry)
Case "+/-"
CallFunction(FunctionEnum.PlusMinus)
Case "¬"
CallFunction(FunctionEnum.Back)
Case "%"
CallFunction(FunctionEnum.Percent)
Case "1/x"
CallFunction(FunctionEnum.Invert)
Case "√"
CallFunction(FunctionEnum.Sqrt)
Case Else
Throw New ApplicationException("Unknown function " + func)
End Select
End Sub
Sub CallFunction(ByVal func As FunctionEnum)
Select Case func
Case FunctionEnum.Ans
Me.Ans()
Case FunctionEnum.Clear
Me.Clear()
Case FunctionEnum.ClearEntry
Me.ClearEntry()
Case FunctionEnum.PlusMinus
Me.PlusMinus()
Case FunctionEnum.Back
Me.Back()
Case FunctionEnum.Percent
Me.Percent()
Case FunctionEnum.Invert
Me.Invert()
Case FunctionEnum.Sqrt
Me.Sqrt()
Case Else
Throw New ApplicationException("Unknown function")
End Select
RaiseEvent UpdatedLog()
End Sub
Private Sub Percent()
Dim percent As Double
Dim left As Double
left = If(leftSide.HasValue, leftSide, 0)
percent = currentValue() / 100
RightSideValue = left * percent
End Sub
Private Sub Invert()
Dim value As Double = currentValue()
RightSideValue = 1 / value
log.Add("reciproc(" & value & ")")
End Sub
Private Sub Sqrt()
Dim value As Double = currentValue()
RightSideValue = Math.Sqrt(value)
log.Add("sqrt(" & value & ")")
End Sub
Private Sub Back()
If rightSide.HasValue And Not Finished Then
Dim str As String
str = rightSide.ToString
str = str.Remove(str.Length - 1, 1)
Double.TryParse(str, RightSideValue)
End If
End Sub
Private Sub PlusMinus()
RightSideValue = currentValue() * -1
End Sub
Private Function Ans() As Double
log.Clear()
RightSideValue = Me.Count()
LeftSideValue = Nothing
Fraction = Nothing
Finished = True
Return RightSideValue
End Function
Private Function OperatorString(ByVal oper As OperatorEnum) As String
Select Case oper
Case OperatorEnum.Addition
OperatorString = "+"
Case OperatorEnum.Division
OperatorString = "/"
Case OperatorEnum.Multiplication
OperatorString = "*"
Case OperatorEnum.Subtraction
OperatorString = "-"
Case Else
Throw New ApplicationException("Unknown Operator")
End Select
End Function
Public Function currentValue() As Double
If rightSide.HasValue Then
Return rightSide
ElseIf leftSide.HasValue Then
Return leftSide
Else
Return 0
End If
End Function
Private Function Count(ByVal left As Double, ByVal right As Double) As Double
Select Case Op
Case OperatorEnum.Addition
Count = left + right
Case OperatorEnum.Subtraction
Count = left - right
Case OperatorEnum.Multiplication
Count = left * right
Case OperatorEnum.Division
If right.Equals(0) Then
Throw New CalculationException("Nelze dělit nulou")
End If
Count = left / right
Case Else
Throw New ApplicationException("Unknown Operator")
End Select
LastOp = Op
Op = Nothing
Return Count
End Function
Private Function Count() As Double
Dim left, right As Double
left = If(leftSide.HasValue, leftSide, rightSide)
If Op Is Nothing Then
If LastOp.HasValue And LastRightSideValue.HasValue Then
Op = LastOp
Return Count(left, LastRightSideValue)
Else
Return currentValue()
End If
End If
right = currentValue()
LastRightSideValue = right
Return Count(left, right)
End Function
End Class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment