;EasyCodeName=RSMeter,1
.Const

MAX_METERS			Equ			20
MAX_LEDS			Equ			40

METER_DATA Struct
	lIndex			LONG		?
	lHeight			LONG		?
	lLedsOn			LONG		?
	lMaxValue		LONG		?
	lMinValue		LONG		?
	lShape			LONG		?
	lValue			LONG		?
	lWidth			LONG		?
	bVertical		LONG		?
	wndOldProc		WNDPROC		?
	hWndMeter		HWND 		?
	hWndOwner		HWND 		?
	hBrush			HBRUSH		?
	hLedOnBrush		HBRUSH		?
	hLedArray		HANDLE		MAX_LEDS Dup(?)
METER_DATA EndS


.Data?

.Data

lRSMeters			LONG		0
lRSMHeight			LONG		6
lRSMWidth			LONG		10
hRSMLabelArray		DWord		20 Dup(0)
hLedOffBrush		HBRUSH		NULL


.Code

CreateMeter Proc Uses Ebx Edi Esi hWndOwner:HWND, x:LONG, y:LONG, lFlags:LONG
	Local dwStyle:DWord, dwExStyle:DWord, sz:SIZEL

	.If hLedOffBrush == NULL
		Invoke GetSysColor, COLOR_BTNFACE
		Sub Eax, 00404040H
		Invoke CreateSolidBrush, Eax
		Mov hLedOffBrush, Eax
	.EndIf
	Invoke GetFreeIndex
	Cmp Eax, (-1)
	Jne @F
L2:	Xor Eax, Eax
	Ret
@@:	Lea Esi, hRSMLabelArray
	Push Eax
	Shl Eax, 2
	Add Esi, Eax
	Invoke GlobalAlloc, GPTR, SizeOf METER_DATA
	Pop Ecx
	Or Eax, Eax
	Jz L2
	Mov DWord Ptr [Esi], Eax
	Mov Esi, Eax
	Mov [Esi].METER_DATA.lIndex, Ecx
	Mov Eax, lRSMHeight
	Mov [Esi].METER_DATA.lHeight, Eax
	Mov Eax, lRSMWidth
	Mov [Esi].METER_DATA.lWidth, Eax
	Mov Eax, hWndOwner
	Mov [Esi].METER_DATA.hWndOwner, Eax
	Mov Eax, lFlags
	Mov Edx, Eax
	And Edx, 007FH
	Mov [Esi].METER_DATA.lShape, Edx
	.If (Eax & RSMETER_VERTICAL)
		Mov [Esi].METER_DATA.bVertical, TRUE
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Dec [Esi].METER_DATA.lHeight
		.EndIf
	.Else
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Dec [Esi].METER_DATA.lWidth
		.EndIf
	.EndIf
	Mov dwStyle, (WS_CHILD Or WS_VISIBLE)
	Mov dwExStyle, 0
	.If Eax == RSMETER_INSET
		Or dwExStyle, WS_EX_STATICEDGE
	.ElseIf Eax == RSMETER_RAISED
		Or dwExStyle, WS_EX_DLGMODALFRAME
	.ElseIf Eax == RSMETER_BORDER
		Or dwStyle, WS_BORDER
	.EndIf
	Invoke GetParentSize, Addr sz
	Invoke CreateWindowEx, 0, TextStr("STATIC"), NULL, (WS_CHILD Or WS_VISIBLE), x, y, sz.x, sz.y, hWndOwner, 0, App.Instance, NULL
	Mov [Esi].METER_DATA.hWndMeter, Eax
	Lea Ebx, [Esi].METER_DATA.hLedArray
	Mov Edi, 1
	Inc lRSMeters
	Invoke CreateSolidBrush, 00FFFF00H
	Mov [Esi].METER_DATA.hLedOnBrush, Eax
	Mov x, 0
	Mov y, 0
@@:	Invoke CreateWindowEx, dwExStyle, TextStr("STATIC"), NULL, dwStyle, x, y, [Esi].METER_DATA.lWidth, [Esi].METER_DATA.lHeight, [Esi].METER_DATA.hWndMeter, Edi, App.Instance, NULL
	Or Eax, Eax
	Jz @F
	Mov DWord Ptr [Ebx], Eax
	.If [Esi].METER_DATA.wndOldProc == NULL
		Invoke GetWindowLong, Eax, GWL_WNDPROC
		Mov [Esi].METER_DATA.wndOldProc, Eax
	.EndIf
	Invoke SetWindowLong, DWord Ptr [Ebx], GWL_USERDATA, Esi
	Invoke SetWindowLong, DWord Ptr [Ebx], GWL_WNDPROC, Addr wndLedsProc
	.If [Esi].METER_DATA.bVertical
		Mov Eax, [Esi].METER_DATA.lHeight
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Inc Eax
		.EndIf
		Add y, Eax
	.Else
		Mov Eax, [Esi].METER_DATA.lWidth
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Inc Eax
		.EndIf
		Add x, Eax
	.EndIf
	Add Ebx, 4
	Inc Edi
	Cmp Edi, (MAX_LEDS + 1)
	Jl @B
	Return [Esi].METER_DATA.lIndex
@@:	Invoke DestroyMeter, [Esi].METER_DATA.lIndex
	Return (-1)
CreateMeter EndP

DestroyMeter Proc Uses Edi Esi lIndex:LONG
	.If SDWord Ptr lIndex >= 0
		Lea Esi, hRSMLabelArray
		Mov Eax, lIndex
		Shl Eax, 2
		Add Esi, Eax
		Push Esi
		Mov Esi, [Esi]
		Or Esi, Esi
		Jz @F
		Lea Esi, [Esi].METER_DATA.hLedArray
		Mov Edi, MAX_LEDS
		.While Edi
			.If DWord Ptr [Esi]
				Invoke DestroyWindow, DWord Ptr [Esi]
				Mov DWord Ptr [Esi], 0
				Add Esi, 4
			.EndIf
			Dec Edi
		.EndW
		Pop Esi
		Invoke GlobalFree, DWord Ptr [Esi]
		Mov DWord Ptr [Esi], 0
		Dec lRSMeters
		.If Zero?
			Invoke DeleteObject, hLedOffBrush
			Mov hLedOffBrush, NULL
		.EndIf
		Return TRUE
	.EndIf
@@:	Xor Eax, Eax
	Ret
DestroyMeter EndP

GetFreeIndex Proc Private Uses Esi
	Lea Esi, hRSMLabelArray
	Xor Ecx, Ecx
	.While Ecx < SDWord Ptr MAX_METERS
		.If DWord Ptr [Esi] == 0
			Return Ecx
		.EndIf
		Add Esi, 4
		Inc Ecx
	.EndW
	Return (-1)
GetFreeIndex EndP

;On enter Esi = Pointer to data
GetParentSize Proc Private Uses Edi lpszSize:DWord
	Mov Edi, lpszSize
	.If [Esi].METER_DATA.bVertical
		Mov Eax, [Esi].METER_DATA.lWidth
		Mov [Edi].SIZEL.x, Eax
		Mov Eax, [Esi].METER_DATA.lHeight
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Inc Eax
		.EndIf
		Mov Ecx, MAX_LEDS
		Mul Ecx
		Mov [Edi].SIZEL.y, Eax
	.Else
		Mov Eax, [Esi].METER_DATA.lHeight
		Mov [Edi].SIZEL.y, Eax
		Mov Eax, [Esi].METER_DATA.lWidth
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Inc Eax
		.EndIf
		Mov Ecx, MAX_LEDS
		Mul Ecx
		Mov [Edi].SIZEL.x, Eax
	.EndIf
	Ret
GetParentSize EndP

;On enter Esi = Pointer to data
ResizeMeter Proc Private Uses Ebx Edi
	Local rc:RECT

	Lea Edi, [Esi].METER_DATA.hLedArray
	Invoke GetWindowRect, DWord Ptr [Edi], Addr rc
	Invoke ScreenToClient, [Esi].METER_DATA.hWndMeter, Addr rc
	Mov Ebx, MAX_LEDS
	.While Ebx
		Invoke MoveWindow, DWord Ptr [Edi], rc.left, rc.top, [Esi].METER_DATA.lWidth, [Esi].METER_DATA.lHeight, TRUE
		Add Edi, 4
		.If [Esi].METER_DATA.bVertical
			Mov Eax, [Esi].METER_DATA.lHeight
			.If [Esi].METER_DATA.lShape == RSMETER_FLAT
				Inc Eax
			.EndIf
			Add rc.top, Eax
		.Else
			Mov Eax, [Esi].METER_DATA.lWidth
			.If [Esi].METER_DATA.lShape == RSMETER_FLAT
				Inc Eax
			.EndIf
			Add rc.left, Eax
		.EndIf
		Dec Ebx
	.EndW
	Ret
ResizeMeter EndP

SetMeterColor Proc Uses Esi lIndex:LONG, crColor:COLORREF
	.If SDWord Ptr lIndex >= 0
		Lea Esi, hRSMLabelArray
		Mov Eax, lIndex
		Shl Eax, 2
		Add Esi, Eax
		Mov Esi, [Esi]
		.If Esi
			Invoke DeleteObject, [Esi].METER_DATA.hLedOnBrush
			Mov Eax, crColor
			Test Eax, 80000000H
			.If !Zero?
				And Eax, 00FFFFFFH
				Invoke GetSysColor, Eax
			.EndIf
			Invoke CreateSolidBrush, Eax
			Mov [Esi].METER_DATA.hLedOnBrush, Eax
		.EndIf
		Return TRUE
	.EndIf
	Xor Eax, Eax
	Ret
SetMeterColor EndP

SetMeterHeight Proc Uses Ebx Edi Esi lIndex:LONG, lHeight:LONG
	Local sz:SIZEL

	.If SDWord Ptr lIndex >= 0
		Lea Esi, hRSMLabelArray
		Mov Eax, lIndex
		Shl Eax, 2
		Add Esi, Eax
		Mov Esi, [Esi]
		Mov Eax, lHeight
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Dec Eax
		.EndIf
		.If Eax != [Esi].METER_DATA.lHeight
			Mov [Esi].METER_DATA.lHeight, Eax
			Invoke GetParentSize, Addr sz
			Invoke SetWindowPos, [Esi].METER_DATA.hWndMeter, NULL, 0, 0, sz.x, sz.y, (SWP_NOZORDER Or SWP_NOMOVE Or SWP_FRAMECHANGED)
			Invoke ResizeMeter
			Return TRUE
		.EndIf
	.EndIf
	Xor Eax, Eax
	Ret
SetMeterHeight EndP

SetMeterMaxValue Proc Uses Esi lIndex:LONG, lMaxValue:LONG
	.If SDWord Ptr lIndex >= 0
		Lea Esi, hRSMLabelArray
		Mov Eax, lIndex
		Shl Eax, 2
		Add Esi, Eax
		Mov Esi, [Esi]
		Mov Eax, lMaxValue
		Mov [Esi].METER_DATA.lMaxValue, Eax
		Return TRUE
	.EndIf
	Xor Eax, Eax
	Ret
SetMeterMaxValue EndP

SetMeterValue Proc Uses Ebx Edi Esi lIndex:LONG, lValue:LONG
	Local lLedsOn:LONG

	.If SDWord Ptr lIndex >= 0
		Lea Esi, hRSMLabelArray
		Mov Eax, lIndex
		Shl Eax, 2
		Add Esi, Eax
		Mov Esi, [Esi]
		Mov Eax, lValue
		.If Eax < SDWord Ptr 0
			Xor Eax, Eax
		.ElseIf Eax > SDWord Ptr [Esi].METER_DATA.lMaxValue
			Mov Eax, [Esi].METER_DATA.lMaxValue
		.EndIf
		Mov [Esi].METER_DATA.lValue, Eax
		Mov Eax, [Esi].METER_DATA.lMaxValue
		Xor Edx, Edx
		Mov Ecx, MAX_LEDS
		Div Ecx
		Mov Ecx, Eax
		Mov Eax, [Esi].METER_DATA.lValue
		Xor Edx, Edx
		Or Ecx, Ecx
		Jz @F
		Div Ecx
		Shr Ecx, 1
		Mov Ebx, Ecx
		Shr Ecx, 1
		Add Ebx, Ecx
		Cmp Edx, Ebx
		Jl @F
		Inc Eax
@@:		Mov [Esi].METER_DATA.lLedsOn, Eax
		Mov lLedsOn, Eax
		Lea Ebx, [Esi].METER_DATA.hLedArray
		Xor Edi, Edi
		Or Eax, Eax
		Jz @F
		.While (Edi <= lLedsOn)
			Mov Eax, [Esi].METER_DATA.hLedOnBrush
			Mov [Esi].METER_DATA.hBrush, Eax
			Invoke InvalidateRect, DWord Ptr [Ebx], NULL, FALSE
			Invoke SendMessage, DWord Ptr [Ebx], WM_PAINT, 0, 0
			Add Ebx, 4
			Inc Edi
		.EndW
@@:		.While (Edi < MAX_LEDS)
			Mov Eax, hLedOffBrush
			Mov [Esi].METER_DATA.hBrush, Eax
			Invoke InvalidateRect, DWord Ptr [Ebx], NULL, FALSE
			Invoke SendMessage, DWord Ptr [Ebx], WM_PAINT, 0, 0
			Add Ebx, 4
			Inc Edi
		.EndW
		Return TRUE
	.EndIf
	Xor Eax, Eax
	Ret
SetMeterValue EndP

SetMeterWidth Proc Uses Ebx Edi Esi lIndex:LONG, lWidth:LONG
	Local sz:SIZEL

	.If SDWord Ptr lIndex >= 0
		Lea Esi, hRSMLabelArray
		Mov Eax, lIndex
		Shl Eax, 2
		Add Esi, Eax
		Mov Esi, [Esi]
		Mov Eax, lWidth
		.If [Esi].METER_DATA.lShape == RSMETER_FLAT
			Dec Eax
		.EndIf
		.If Eax != [Esi].METER_DATA.lWidth
			Mov [Esi].METER_DATA.lWidth, Eax
			Invoke GetParentSize, Addr sz
			Invoke SetWindowPos, [Esi].METER_DATA.hWndMeter, NULL, 0, 0, sz.x, sz.y, (SWP_NOZORDER Or SWP_NOMOVE Or SWP_FRAMECHANGED)
			Invoke ResizeMeter
			Return TRUE
		.EndIf
	.EndIf
	Xor Eax, Eax
	Ret
SetMeterWidth EndP

wndLedsProc Proc Private Uses Ebx Edi Esi hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
	Local ps:PAINTSTRUCT

	Invoke GetWindowLong, hWnd, GWL_USERDATA
	Mov Esi, Eax
	.If uMsg == WM_ERASEBKGND
		Return TRUE
	.ElseIf uMsg == WM_PAINT
		Invoke BeginPaint, hWnd, Addr ps
		Invoke GetClientRect, hWnd, Addr ps.rcPaint
		Invoke FillRect, ps.hdc, Addr ps.rcPaint, [Esi].METER_DATA.hBrush
		Invoke EndPaint, hWnd, Addr ps
		Xor Eax, Eax
		Ret
	.EndIf
	Invoke CallWindowProc, [Esi].METER_DATA.wndOldProc, hWnd, uMsg, wParam, lParam
	Ret
wndLedsProc EndP

