Files
overtime-guard/AnalogClock.bas

234 lines
7.8 KiB
QBasic

B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=13
@EndOfDesignText@
Sub Class_Globals
Private xui As XUI
Private pnlClock As Panel ' Pannello in cui disegnare l'orologio
Private cvsClock As B4XCanvas ' Canvas per disegnare l'orologio
Private clockDiameter As Float ' Diametro dell'orologio (in pixel)
Private centerX As Float ' Coordinata X del centro dell'orologio
Private centerY As Float ' Coordinata Y del centro dell'orologio
Private segments As List ' Segmenti cronologici registrati
' Parametri di spessore
Private quadrantStrokeWidth As Float = 5dip
Private hourTickStrokeWidth As Float = 5dip
Private minuteTickStrokeWidth As Float = 2dip
Private intervalArcStrokeWidth As Float = 5dip
Private hourHandStrokeWidth As Float = 8dip
Private minuteHandStrokeWidth As Float = 5dip
Private baseDurationMs As Long
Private activeDurationMs As Long
Private activeColor As Int
Private activeIsPause As Boolean
Private hasActiveSegment As Boolean
End Sub
' Inizializza l'orologio
Public Sub Initialize(ParentPanel As Panel, PercentageOfWidth As Float)
pnlClock = ParentPanel
cvsClock.Initialize(pnlClock)
segments.Initialize
baseDurationMs = 12 * DateTime.TicksPerHour
SetClockSize(PercentageOfWidth)
End Sub
' Imposta la durata piena del quadrante. Le pause gialle vengono aggiunte a parte.
Public Sub SetBaseDuration(DurationMs As Long)
baseDurationMs = DurationMs
DrawClock
End Sub
' Rimuove tutti i segmenti registrati.
Public Sub ClearSegments
If segments.IsInitialized = False Then segments.Initialize
segments.Clear
hasActiveSegment = False
activeDurationMs = 0
DrawClock
End Sub
' Aggiunge un segmento concluso.
Public Sub AddSegment(DurationMs As Long, SegmentColor As Int, IsPause As Boolean)
If DurationMs <= 0 Then Return
Dim segment As Map
segment.Initialize
segment.Put("duration", DurationMs)
segment.Put("color", SegmentColor)
segment.Put("pause", IsPause)
segments.Add(segment)
DrawClock
End Sub
' Imposta il segmento in corso, non ancora concluso.
Public Sub SetActiveSegment(DurationMs As Long, SegmentColor As Int, IsPause As Boolean)
activeDurationMs = Max(0, DurationMs)
activeColor = SegmentColor
activeIsPause = IsPause
hasActiveSegment = activeDurationMs > 0
DrawClock
End Sub
Public Sub ClearActiveSegment
hasActiveSegment = False
activeDurationMs = 0
DrawClock
End Sub
' Imposta la dimensione dell'orologio come percentuale della larghezza del pannello
Public Sub SetClockSize(PercentageOfWidth As Float)
clockDiameter = pnlClock.Width * PercentageOfWidth / 100
centerX = pnlClock.Width / 2
centerY = pnlClock.Height / 2
DrawClock
End Sub
' Imposta lo spessore delle varie linee
Public Sub SetStrokeWidths(quadrantWidth As Float, hourTickWidth As Float, minuteTickWidth As Float, intervalArcWidth As Float, hourHandWidth As Float, minuteHandWidth As Float)
quadrantStrokeWidth = quadrantWidth
hourTickStrokeWidth = hourTickWidth
minuteTickStrokeWidth = minuteTickWidth
intervalArcStrokeWidth = intervalArcWidth
hourHandStrokeWidth = hourHandWidth
minuteHandStrokeWidth = minuteHandWidth
DrawClock
End Sub
' Cancella il canvas riempiendolo con un colore specifico
Private Sub ClearCanvas(color As Int)
cvsClock.DrawRect(cvsClock.TargetRect, color, True, 0)
cvsClock.Invalidate
End Sub
' Disegna l'orologio
Public Sub DrawClock
cvsClock.Initialize(pnlClock)
' Cancella il canvas
ClearCanvas(Colors.White)
' Disegna il cerchio esterno
cvsClock.DrawCircle(centerX, centerY, clockDiameter / 2, Colors.Black, False, quadrantStrokeWidth)
' Disegna i segmenti di lavoro / pausa / straordinario
DrawSegments
' Disegna le tacche delle ore e dei minuti
DrawTicks
' Disegna le lancette
Dim now As Long = DateTime.Now
Dim Hours As Int = DateTime.GetHour(now) Mod 12
Dim Minutes As Int = DateTime.GetMinute(now)
Dim Seconds As Int = DateTime.GetSecond(now)
' Lancetta ore
Dim HourAngle As Float = -90 + Hours * 30 + Minutes / 2
DrawHand(centerX, centerY, clockDiameter * 0.25, HourAngle, hourHandStrokeWidth, Colors.Black)
' Lancetta minuti
Dim MinuteAngle As Float = -90 + Minutes * 6
DrawHand(centerX, centerY, clockDiameter * 0.4, MinuteAngle, minuteHandStrokeWidth, Colors.Blue)
' Lancetta secondi
Dim SecondAngle As Float = -90 + Seconds * 6
DrawHand(centerX, centerY, clockDiameter * 0.45, SecondAngle, 2dip, Colors.Red)
' Aggiorna il pannello
pnlClock.Invalidate
End Sub
Private Sub DrawSegments
If segments.IsInitialized = False Then Return
Dim totalPauseMs As Long = 0
Dim totalRecordedMs As Long = 0
For Each segment As Map In segments
Dim duration As Long = segment.Get("duration")
totalRecordedMs = totalRecordedMs + duration
If segment.Get("pause") = True Then totalPauseMs = totalPauseMs + duration
Next
If hasActiveSegment Then
totalRecordedMs = totalRecordedMs + activeDurationMs
If activeIsPause Then totalPauseMs = totalPauseMs + activeDurationMs
End If
Dim totalDisplayMs As Long = Max(baseDurationMs, totalRecordedMs)
If totalDisplayMs <= 0 Then Return
Dim startAngle As Float = -90
Dim radius As Float = clockDiameter / 2 - 22dip
For Each segment As Map In segments
Dim sweepAngle As Float = 360 * segment.Get("duration") / totalDisplayMs
DrawPieSegment(startAngle, sweepAngle, segment.Get("color"), radius)
startAngle = startAngle + sweepAngle
Next
If hasActiveSegment Then
Dim activeSweepAngle As Float = 360 * activeDurationMs / totalDisplayMs
DrawPieSegment(startAngle, activeSweepAngle, activeColor, radius)
End If
End Sub
Private Sub DrawPieSegment(startAngle As Float, sweepAngle As Float, color As Int, radius As Float)
If sweepAngle <= 0 Then Return
Dim steps As Int = Max(2, Ceil(sweepAngle / 4))
Dim path As B4XPath
path.Initialize(centerX, centerY)
For i = 0 To steps
Dim angle As Float = startAngle + sweepAngle * i / steps
Dim x As Float = centerX + radius * CosD(angle)
Dim y As Float = centerY + radius * SinD(angle)
path.LineTo(x, y)
Next
path.LineTo(centerX, centerY)
cvsClock.DrawPath(path, color, True, 0)
End Sub
' Disegna una singola lancetta
Private Sub DrawHand(x As Float, y As Float, length As Float, angle As Float, width As Float, color As Int)
Dim endX As Float = x + length * CosD(angle)
Dim endY As Float = y + length * SinD(angle)
cvsClock.DrawLine(x, y, endX, endY, color, width)
End Sub
' Disegna le tacche delle ore e dei minuti
Private Sub DrawTicks
For i = 0 To 59
Dim angle As Float = -90 + i * 6
Dim startX As Float
Dim startY As Float
Dim endX As Float
Dim endY As Float
If i Mod 5 = 0 Then
' Tacca delle ore
startX = centerX + (clockDiameter / 2 - 20dip) * CosD(angle)
startY = centerY + (clockDiameter / 2 - 20dip) * SinD(angle)
endX = centerX + (clockDiameter / 2 - 5dip) * CosD(angle)
endY = centerY + (clockDiameter / 2 - 5dip) * SinD(angle)
cvsClock.DrawLine(startX, startY, endX, endY, Colors.Black, hourTickStrokeWidth)
Else
' Tacca dei minuti
startX = centerX + (clockDiameter / 2 - 10dip) * CosD(angle)
startY = centerY + (clockDiameter / 2 - 10dip) * SinD(angle)
endX = centerX + (clockDiameter / 2 - 5dip) * CosD(angle)
endY = centerY + (clockDiameter / 2 - 5dip) * SinD(angle)
cvsClock.DrawLine(startX, startY, endX, endY, Colors.Black, minuteTickStrokeWidth)
End If
Next
End Sub
' Aggiorna l'orologio ogni secondo
Public Sub StartClock
Dim timer As Timer
timer.Initialize("timer", 1000)
timer.Enabled = True
End Sub
' Evento del timer per aggiornare l'orologio
Private Sub timer_Tick
DrawClock
End Sub