Тема: AHK v2: Class Рисование графиков из массива данных
Конвертация этой версии.
Описание и примеры добавлю позже, сейчас сил нет, читайте описание для первой версии там почти тоже самое.
Неоформленный пример:
arr3:=[]
loop 7
arr3.Push([])
c:=1
d:=0
e:=1
a:=0
t:=0
b:=0
arr:=[]
settimer ddd,150
settimer aaa,500
gra:=Graph()
gra.show()
gra.ArrName[1]:="кг"
gra.ArrName[2]:="Двигатель"
gra.ArrName[3]:="Температура"
gra.ArrName[4]:="Разряжение"
gra.ArrName[5]:="Натяжение"
gra.ArrName[6]:="Угол"
gra.ArrName[7]:="Ничего"
gra.DataArray:=arr3
d:=e:=-1300
f1::
{
gra.show()
}
f2::
{
if (gra.DataArray=arr3)
gra.DataArray:=arr
else
gra.DataArray:=arr3
}
ddd()
{
global
a+=0.1
if (b<-1 or b>1)
t:=!t
if t
b+=0.005
else
b-=0.005
if (b>1)
{
d:=random(-1000000000,1000000000)
e:=random(-1000000000,1000000000)
c:=random(0.5,1.5)
}
var:=random(50.5,100.5)
shift:=0
Val:=(sin(a)*var*b+shift)
arr.Push(sin(a))
arr3[1].Push(Val-30)
arr3[4].Push([Val,A_Now,A_MSec])
arr3[3].Push([-Val,A_Now,A_MSec])
arr3[5].Push([cos(a*a)*0.1,A_Now,A_MSec])
arr3[6].Push([cos(-a*2)*10*b+10,A_Now,A_MSec])
arr3[7].Push([random(-1000000000,1000000000),A_Now,A_MSec])
}
aaa()
{
static bool:=1
bool:=!bool
arr3[2].Push([bool,A_Now,A_MSec])
}
Esc::
{
global
gra:=""
exitapp
}
Class:
class Graph
{
; #requires AutoHotkey v2.0.19
static hModule:=DllCall("LoadLibrary","str","gdiplus","Ptr")
static pToken:=0, InstanceCount:=0
static WinText:="Special text to identify the ownership of the Graph window."
;gdiplus\
static hGdipCreateFont:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateFont","Ptr")
static hGdipCreateFontFamilyFromName:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateFontFamilyFromName","Ptr")
static hGdipCreateFromHDC:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateFromHDC","Ptr")
static hGdipCreatePen1:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreatePen1","Ptr")
static hGdipCreateSolidFill:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateSolidFill","Ptr")
static hGdipCreateStringFormat:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateStringFormat","Ptr")
static hGdipDeleteBrush:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDeleteBrush","Ptr")
static hGdipDeleteFont:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDeleteFont","Ptr")
static hGdipDeleteFontFamily:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDeleteFontFamily","Ptr")
static hGdipDeletePen:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDeletePen","Ptr")
static hGdipDeleteStringFormat:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDeleteStringFormat","Ptr")
static hGdipDrawEllipse:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDrawEllipse","Ptr")
static hGdipDrawLine:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDrawLine","Ptr")
static hGdipDrawLines:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDrawLines","Ptr")
static hGdipDrawString:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDrawString","Ptr")
static hGdipFillRectangle:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipFillRectangle","Ptr")
static hGdiplusShutdown:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdiplusShutdown","Ptr")
static hGdiplusStartup:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdiplusStartup","Ptr")
static hGdipMeasureString:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipMeasureString","Ptr")
static hGdipSetSmoothingMode:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipSetSmoothingMode","Ptr")
static hGdipSetStringFormatAlign:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipSetStringFormatAlign","Ptr")
static hGdipSetTextRenderingHint:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipSetTextRenderingHint","Ptr")
static hGdipReleaseDC:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipReleaseDC","Ptr")
static hGdipDeleteGraphics:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDeleteGraphics","Ptr")
static hGdipCreateBitmapFromHBITMAP:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateBitmapFromHBITMAP","Ptr")
static hGdipCreateTexture2:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipCreateTexture2","Ptr")
static hGdipDisposeImage:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDisposeImage","Ptr")
static hGdipDrawRectangle:=DllCall("GetProcAddress","Ptr",Graph.hModule,"AStr","GdipDrawRectangle","Ptr")
static min:=-9223372036854775808
static max:= 9223372036854775807
static MaxTime:=30*24*3600000 ; миллисекунд
static WheelUp:=false
static WheelDown:=false
static HotKeymW:=0
__Delete()
{
if this.Deleted
return
this.Deleted:=true
loop this.RefCount
ObjAddRef(ObjPtr(this))
; tooltip "Деструктор вызван.`n" Graph.InstanceCount "`n" this.Name
; sleep 1000
; tooltip
settimer this.UpdateTimer,0
this.UpdateTimer:=""
DllCall(Graph.hGdipDeleteGraphics,"UPtr",this.pGraphics)
DllCall("SelectObject","Ptr",this.hDC,"Ptr",this.obm)
DllCall("DeleteObject","UPtr",this.hBitmap)
DllCall("ReleaseDC","Ptr",this.GuiGDIP.Hwnd,"Ptr",this.hDC)
this.GuiHelp.Destroy()
this.GuiGoToT.Destroy()
this.GuiGDIP.Destroy()
this.GuiGraph.Destroy()
this.GraphMenu.Delete()
this.GraphMenuSettings.Delete()
loop this.Child.Length
{
ObjAddRef(ObjPtr(this))
this.Child[a_index]:=""
}
Graph.InstanceCount--
if (Graph.InstanceCount=0)
{
DllCall(Graph.hGdiplusShutdown,"Ptr",Graph.pToken)
Graph.pToken:=""
}
}
mi:={MenuAlwaysOnTop:"Всегда поверх окон"
,MenuAutoScale:"Автомасштаб"
,MenuSmooth:"Сглаживать ступеньки"
,MenuFlFt:"Количество знаков после запятой..."
,MenuScaleXByTime:"Масштабировать X по времени"
,MenuScaleXByDots:"Масштабировать X по точкам"
,MenuResetFont:"Сбросить размер шрифта"
,MenuGColor:"Выбрать цвет графика..."
,MenuName:"Изнменить имя выбранного графика..."
,MenuSave:"Сохранить график в файл..."
,MenuLoad:"Загрузить график из файла..."
,MenuClose:"Х "
,MenuPause:"(||)"
,MenuForward:"(>|)"
,MenuBackward:"(|<)"
,MenuGoTo:"Перейти"
,MenuMarkers:"Маркеры"
,MenuHelp:"Справка"
,Settings:"Настр."}
__New(Name:="",UpdatePeriod:=50)
{
; Запустить библиотеку гдиплюс
if !Graph.pToken
{
si:=Buffer(A_PtrSize=8 ? 24 : 16,0)
NumPut("UChar",1,si,0)
DllCall(Graph.hGdiplusStartup,"UPtr*",&pToken:=0,"Ptr",si.Ptr,"Ptr",0)
Graph.pToken:=pToken
}
Graph.InstanceCount++
if !Name
this.Name:="График " Graph.InstanceCount
; Инициализация переменных
this.ArrName:=[]
loop 10
this.ArrName.Push("")
this.IsChild:=false
this.Child:=[]
this.Parent:=0
this.Deleted:=false
this.SaveArrName:=[]
this.SetParentOnce:=false
this.CreateTime:=[A_Now,A_msec]
this.Data:=[]
this.NewData:=""
this.Loaded:=0
this.FloatFormat:=3
this.Drawing:=false
this.UpdatePeriod:=UpdatePeriod
this.hFormat:=0
this.hFamily:=0
this.hFont:=0
this.prevRenderingHint:=""
this.prevBrushColor:=0
this.prevPenColor:=0
this.prevNoWrap:=0
this.prevVertical:=0
this.prevFont:=""
this.prevSize:=0
this.prevfStyle:=""
this.prevRenderingHint:=""
this.prevColour:=0
this.pBrush:=0
this.pPen:=0
this.FontpBrush:=0
this.GPosW:=0
this.GPosH:=0
this.GPosH_:=0
this.Pause:=false
this.OScale:=true
this.GetmCoordOnce:=false
this.GetStartPosRectOnce:=false
this.ZoomX:=100
this.ZoomT:=30000
this.OldZoomX:=this.ZoomX
this.OldZoomT:=this.ZoomT
this.SaveZoomX:=this.ZoomX
this.SaveZoomT:=this.ZoomT
this.ShowZoomTip:=0
this.XTOffset:=0
this.X_Offset:=0
this.ZeroPos:=30
this.ZeroPosU:=1
this.GPosH:=160
this.AStartTime:=0
this.StampOffset:=0
this.MarkerOffset:=0
this.StampsNum:=5
this.XMarker:=[-9999,-9999]
this.MenuOffset:=0
this.Old_XTOffset:=0
this.OldXTOffset:=0
this.Sel:=1
this.Proc:=0
this.StartTime:=0
this.OldmX:=0
this.OldmY:=0
this.FontpBrush:=0
this.SaveStrt:=[0,0]
this.ShowMarkers:=false
this.OffsetSetting:=false
this.ShiftStrt:=false
this.MouseMoved:=false
this.OldX_Offset:=0
this.StampPos:={X:0,Y:0,W:0,H:this.GPosH,Chars:0,Lines:0}
this.ETPos:={X:0,Y:0,W:0,H:0,Chars:0,Lines:0}
this.TipPos:={X:0,Y:0,W:0,H:0,Chars:0,Lines:0}
this.iZoomPos:={X:0,Y:0,W:0,H:0,Chars:0,Lines:0}
this.OScalePos:={X:0,Y:0,W:0,H:0,Chars:0,Lines:0}
this.Setting:=false
this.RectZoom:=false
this.XMarkerOnce:=false
this.AlwaysOnTop:=false
this.PrevW:=0
this.PrevH:=0
this.TimeOut:=false
this.TOZoomX:=0
this.TOZoomT:=0
; Создать графику
this.Create()
this.ReInit()
; Настройки по умолчанию
this.Font:="Lucida Console" ; шрифт
this.FontSize:=12 ; размер шрифта
this.SetFont(this.Font,this.FontSize)
this.Font_Colour:=0xff000000 ; цвет шрифта
this.Font_Back:=0xd0ffffff ; цвет фона шрифта
this.WhiteBrush:=0xffffffff ; для общего фона
this.GrayPen:=0xaa808080 ; для оси
this.GrayPen2:=0xaae0e0e0 ; для оси
this.RedPen:=0xffff0000 ; для маркера
this.LightGreenBrush:=0xffd5ffd5 ; для фона информации
this.LightBlueBrush:=0xffd5d5ff ; для фона Меню
this.BluePen:=0xff0000ff ; для графика
s:=this.mi.MenuClose this.mi.MenuPause this.mi.MenuForward this.mi.MenuBackward this.mi.MenuGoTo this.mi.MenuMarkers this.mi.Settings this.mi.MenuHelp
loop 12
s.="_"
w:=this.MeasureString(s,this.CreateRectF(0,0,1400,100))
; смещение исходной высоты если нет данных
this.MessagePos:={X:0,Y:0,W:0,H:w.H,Chars:0,Lines:0}
; Добавление меню
; Меню настроек
this.GraphMenuSettings:=Menu()
obm:=ObjBindMethod(this,"MenuSave")
this.GraphMenuSettings.add(this.mi.MenuSave,obm)
obm:=ObjBindMethod(this,"MenuLoad")
this.GraphMenuSettings.add(this.mi.MenuLoad,obm)
this.GraphMenuSettings.add()
obm:=ObjBindMethod(this,"MenuAlwaysOnTop")
this.GraphMenuSettings.add(this.mi.MenuAlwaysOnTop,obm)
obm:=ObjBindMethod(this,"MenuAutoScale")
this.GraphMenuSettings.add(this.mi.MenuAutoScale,obm)
this.GraphMenuSettings.check(this.mi.MenuAutoScale)
obm:=ObjBindMethod(this,"MenuSmooth")
this.GraphMenuSettings.add(this.mi.MenuSmooth,obm)
this.GraphMenuSettings.check(this.mi.MenuSmooth)
obm:=ObjBindMethod(this,"MenuFlFt")
this.GraphMenuSettings.add(this.mi.MenuFlFt,obm)
this.GraphMenuSettings.add()
obm:=ObjBindMethod(this,"MenuScaleXByTime")
this.GraphMenuSettings.add(this.mi.MenuScaleXByTime,obm,"+Radio")
this.GraphMenuSettings.check(this.mi.MenuScaleXByTime)
this.ScaleXByTime:=true
obm:=ObjBindMethod(this,"MenuScaleXByDots")
this.GraphMenuSettings.add(this.mi.MenuScaleXByDots,obm,"+Radio")
this.GraphMenuSettings.add()
obm:=ObjBindMethod(this,"MenuName")
this.GraphMenuSettings.add(this.mi.MenuName,obm)
obm:=ObjBindMethod(this,"MenuGColor")
this.GraphMenuSettings.add(this.mi.MenuGColor,obm)
obm:=ObjBindMethod(this,"MenuResetFont")
this.GraphMenuSettings.add(this.mi.MenuResetFont,obm)
; основное меню
this.GraphMenu:=MenuBar()
; obm:=ObjBindMethod(this,"MenuClose")
; this.GraphMenu.add(this.mi.MenuClose,obm)
this.GraphMenu.add(this.mi.Settings,this.GraphMenuSettings)
obm:=ObjBindMethod(this,"MenuBackward")
this.GraphMenu.add(this.mi.MenuBackward,obm)
obm:=ObjBindMethod(this,"MenuPause")
this.GraphMenu.add(this.mi.MenuPause,obm)
obm:=ObjBindMethod(this,"MenuForward")
this.GraphMenu.add(this.mi.MenuForward,obm)
obm:=ObjBindMethod(this,"MenuGoTo")
this.GraphMenu.add(this.mi.MenuGoTo,obm)
obm:=ObjBindMethod(this,"MenuMarkers")
this.GraphMenu.add(this.mi.MenuMarkers,obm)
obm:=ObjBindMethod(this,"MenuHelp")
this.GraphMenu.add(this.mi.MenuHelp,obm)
; Создание основного окна
this.GuiGraph:=Gui("+MinSize400x100 +Resize",this.Name)
this.GuiGraph.MarginX:=0
this.GuiGraph.MarginY:=0
this.GuiGraph.MenuBar:=this.GraphMenu
this.GuiGraph.Add("Text","w0 h0",Graph.WinText)
obm:=ObjBindMethod(this,"DropFiles")
this.GuiGraph.OnEvent("DropFiles",obm)
obm:=ObjBindMethod(this,"Hide")
this.GuiGraph.OnEvent("Close",obm)
; Создание окна отрисовки графики
this.GuiGDIP:=Gui("+owner" this.GuiGraph.Hwnd " -Caption +ToolWindow +E0x08080020") ; WS_EX_LAYERED := 0x80000
this.GuiGDIP.Show("NoActivate x0 y0 w1 h1")
; Создание окна перехода по времени
this.GuiGoToT:=Gui("+owner" this.GuiGraph.Hwnd " -sysmenu -Resize","Перейти на время")
this.GuiGoToT.SetFont("s10")
this.hTT:=this.GuiGoToT.Add("DateTime","xm+1","HH:mm:ss dd.MM.yyyy")
obm:=ObjBindMethod(this,"TTOk")
this.GuiGoToT.Add("Button","xm+5 y+5","Ok").OnEvent("Click",obm)
obm:=ObjBindMethod(this,"TTCancel")
this.GuiGoToT.Add("Button","x+10","Отмена").OnEvent("Click",obm)
; Создание окна перехода к точке
this.GuiGoToX:=Gui("+owner" this.GuiGraph.Hwnd " -sysmenu -Resize","Перейти к точке")
this.GuiGoToX.SetFont("s10")
this.hTX:=this.GuiGoToX.Add("Edit","xm+1 w150 Number",1)
obm:=ObjBindMethod(this,"TXOk")
this.GuiGoToX.Add("Button","xm+5 y+5","Ok").OnEvent("Click",obm)
obm:=ObjBindMethod(this,"TXCancel")
this.GuiGoToX.Add("Button","x+10","Отмена").OnEvent("Click",obm)
; Создание окна справки
this.GuiHelp:=Gui("+owner" this.GuiGraph.Hwnd " -sysmenu -Resize","Справка")
this.GuiHelp.SetFont("s10")
HelpText:=
(
"Левая кнопка мыши - перемещение графика.
Правая кнопка мыши - выделение и увеличение выделенного участка.
Клик правой кнопкой - возврат к предыдущему масштабу после увеличения."
)
this.GuiHelp.Add("Text",,HelpText)
obm:=ObjBindMethod(this,"HelpClose")
this.GuiHelp.Add("Button","xm+10 y+5","Закрыть").OnEvent("Click",obm)
; Создание окна изменения имени выбранного графика
this.GuiName:=Gui("+owner" this.GuiGraph.Hwnd " -sysmenu -Resize","Имя графика")
this.GuiName.SetFont("s10")
this.GuiNameVal:=this.GuiName.Add("Edit","xm+1 w150",3)
obm:=ObjBindMethod(this,"NameOk")
this.GuiName.Add("Button","xm+5 y+5","Ok").OnEvent("Click",obm)
obm:=ObjBindMethod(this,"NameCancel")
this.GuiName.Add("Button","x+10","Отмена").OnEvent("Click",obm)
; Создание окна изменения значения настройки
this.GuiVal:=Gui("+owner" this.GuiGraph.Hwnd " -sysmenu -Resize","Изменить")
this.GuiVal.SetFont("s10")
this.GuiValText1:=this.GuiVal.Add("Text","xm+10 w350")
this.GuiValVal:=this.GuiVal.Add("Edit","xm+5 y+5 wp Number",3)
this.GuiValText2:=this.GuiVal.Add("Text","xm+10 y+1 wp")
obm:=ObjBindMethod(this,"ValAcc")
this.GuiVal.Add("Button","xm+5 y+5","Применить").OnEvent("Click",obm)
obm:=ObjBindMethod(this,"ValOk")
this.GuiVal.Add("Button","x+10","Ok").OnEvent("Click",obm)
obm:=ObjBindMethod(this,"ValCancel")
this.GuiVal.Add("Button","x+10","Отмена").OnEvent("Click",obm)
this.Whichval:=""
; Запомнить метку для таймера
this.UpdateTimer:=ObjBindMethod(this,"UpdateGraph")
this.GuiHiden:=true
; this.UpdateGraph()
this.RefCount:=30
loop this.RefCount
ObjRelease(ObjPtr(this))
/*
форматы обрабатывемых данных
Data:=[1,2,3,4,5,6,76,56,3,45,6,22,45,234]
- простой массив значений
Data:=[[1,A_Now],[2,A_Now],[3,A_Now],[4,A_Now]]
- массив с меткой времени [[значение,время],[значение,время]...]
Data:=[[1,A_Now,A_MSec],[2,A_Now,A_MSec],[3,A_Now,A_MSec],[4,A_Now,A_MSec]]
- массив с меткой времени с миллисекундами [[значение,время,миллисекунды],[значение,время,миллисекунды]...]
Data:=[[1,2],[[1,A_Now],[2,A_Now]],[[1,A_Now,A_MSec],[2,A_Now,A_MSec]]]
- массив любых выше перечисленных массивов
*/
}
DataArray
{
set
{
if this.SaveArrName.Length
{
this.ArrName:=this.SaveArrName.Clone()
this.SaveArrName:=[]
}
this.Loaded:=2
this.NewData:=Value
}
get
{
return this.Data
}
}
HitBox(X,Y,Rect)
{
return (X>Rect.X and X<Rect.X+Rect.W and Y>Rect.Y and Y<Rect.Y+Rect.H)
}
;/////////////////////////////////////////////////////////////////////////////////////////////////
;|///////|///////|///////|///////|///////|///////|///////|///////|///////|///////|///////|///////|
;||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////||
;|||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||
;||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/||||
ReInit()
{
this.prevArrSize:=[]
this.SearchStop:=[]
this.SearchSkip:=[]
this.LineW:=[]
this.Transp:=[]
this.Smooth:=[]
this.AutoScale:=[]
this.SaveAutoScale:=[]
this.SaveYScale:=[]
this.GHide:=[]
this.YScale:=[]
this.Pen:=[]
this.Hue:=[]
this.ArrSize:=[]
this.prev_ArrSize:=[]
this.StampT:=[]
this.LockYP:=[]
this.LockYM:=[]
this.Lock_hi_lim:=[]
this.Lock_lo_lim:=[]
this.Val_UnderGraph_Drawed:=[]
this.UnderGX:=[]
this.UnderGY:=[]
this.UnderGV:=[]
this.Sel:=1
this.ZeroPos:=this.GPosH//3
this.TimeStampExist:=[]
}
GetTime()
{
t1:=A_Now
t2:=A_MSec
while (t2<5)
{
t1:=A_Now
t2:=A_MSec
}
return [t1,t2]
}
UpdateGraph()
{
ListLines 0
ObjAddRef(ObjPtr(this))
if this.GuiHiden
{
ObjRelease(ObjPtr(this))
return
}
this.Drawing:=true
if (this.Loaded and !this.NewData)
{
this.MenuForward()
if (this.Loaded=1)
this.Pause:=true
this.Loaded:=0
}
if this.NewData
{
this.ReInit()
this.Data:=this.NewData
this.NewData:=""
}
DllCall("QueryPerformanceFrequency", "Int64*",&frequency:=0)
DllCall("QueryPerformanceCounter","Int64*",&EndTime:=0)
CycleTime:=round((EndTime-this.StartTime)/frequency*1000,1)
DllCall("QueryPerformanceCounter", "Int64*",&StartTime:=0)
this.StartTime:=StartTime
; Взять координаты мыши
SaveCoordMode:=A_CoordModeMouse
CoordMode "Mouse","Client"
MouseGetPos(&mX,&mY,&mW,&mC,2)
CoordMode "Mouse",SaveCoordMode
MouseIn:=(this.GuiGraph.hwnd=mW and mY>0)
DeltaX:=this.OldmX-mX
DeltaY:=this.OldmY-mY
this.Pos:=this.DrawString(0,0,0,,,,this.Font_Colour,this.Font_Back)
; очистить поле
this.FillRectangle(this.WhiteBrush,0,0,this.GPosW,this.GPosH_)
; Добавление координаты маркеру
if (MouseIn and getkeystate("RButton","P") and mY<this.GPosH and !this.XMarkerOnce)
{
this.XMarkerOnce:=true
this.XMarker[2]:=mX
}
else if (this.XMarkerOnce and !getkeystate("RButton","P"))
this.XMarkerOnce:=false
; Пауза скролинга для режима отображения по времени
if this.Pause
{
this.XTOffset+=CycleTime
this.OldXTOffset+=CycleTime
}
; Определение массива массивов
ArAr:=false
if (this.Data.Length and isObject(this.Data[1])) ; and this.Data[1].Length)
{
if !this.Data[1].Length
{
this.MessagePos:=this.DrawString("Нет данных",this.GPosW//2-this.MessagePos.W//2,this.GPosH//2-this.MessagePos.H//2,,,,this.Font_Colour,this.Font_Back)
if !this.GuiHiden
this.Update()
ObjRelease(ObjPtr(this))
return
}
ArAr:=isObject(this.Data[1][1])
if (!ArAr and this.Data[1].Has(2))
ArAr:=strlen(this.Data[1][2])!=14
}
Ars:=ArAr?this.Data.Length:1
loop Ars
{
this.Proc:=a_index
if (this.prevArrSize.Length<this.Proc)
{
if (this.Proc>100)
this.ArrName.Push("")
this.prevArrSize.Push(1)
this.SearchStop.Push(true)
this.SearchSkip.Push(0)
this.LineW.Push(1.0)
this.Transp.Push(255)
this.Smooth.Push(true)
this.AutoScale.Push(true)
this.SaveAutoScale.Push(false)
this.GHide.Push(false)
this.YScale.Push(1)
this.SaveYScale.Push(1)
this.Pen.Push("")
this.Hue.Push(512)
this.ArrSize.Push(0)
this.prev_ArrSize.Push(0)
this.LockYP.Push(0)
this.LockYM.Push(0)
this.Val_UnderGraph_Drawed.Push(false)
this.UnderGX.Push(0)
this.UnderGY.Push(0)
this.UnderGV.Push(0)
this.Lock_hi_lim.Push(false)
this.Lock_lo_lim.Push(false)
this.StampT.Push([this.CreateTime])
this.TimeStampExist.Push(false)
this.UpdateMenu()
}
if (this.Pen[this.Proc]="")
{
Hue:=random(0,255)
if (this.Proc>1 and this.Hue[this.Proc-1])
{
loop 100
{
Hue:=random(0,255)
free:=true
for v in this.Hue
{
if (abs(v-Hue)<30)
{
free:=false
break
}
}
if free
break
}
}
this.Pen[this.Proc]:=this.AHSVToARGB(this.Transp[this.Proc],Hue,255,192)
this.Hue[this.Proc]:=Hue
}
if (this.SearchSkip[this.Proc] and this.Old_XTOffset>this.XTOffset)
{
this.SearchStop[this.Proc]:=true
this.SearchSkip[this.Proc]:=0
}
}
this.Old_XTOffset:=this.XTOffset
XMarker:=[false,false]
XMarkeri:=[0,0]
MarkerTime:=[1601,1601]
MarkerTimeMs:=[0,0]
XMarkerCoord:=[0,0]
MarkerValue:=["",""]
MarkerText:=["",""]
MarkerDText:=""
MarkerMin:=0
MarkerMax:=0
StDeviation:=""
MarkerMean:=""
StampPos:={X:0,Y:0,W:0,H:this.GPosH+this.MessagePos.H*2,Chars:0,Lines:0}
prevStampPos:={X:0,Y:0,W:0,H:this.GPosH,Chars:0,Lines:0}
Stamp:=false
GetSizeOnce:=false
prevCoordY:=0
ValNum:=0
Deviation:=0
this.ValTipPos:={X:0,Y:0,W:0,H:0,Chars:0,Lines:0}
PrevtmpY:=0
loop________Start:
loop Ars
{
this.Proc:=a_index
if ArAr
this.pData:=this.Data[this.Proc]
else
this.pData:=this.Data
ArrSize:=this.pData.Length
this.ArrSize[this.Proc]:=ArrSize
this.TimeStampMillis:=false
if (ArrSize and IsObject(this.pData[ArrSize]))
{
if this.pData[ArrSize].Has(2)
this.TimeStampExist[this.Proc]:=strlen(this.pData[ArrSize][2])=14
if this.pData[ArrSize].Has(3)
this.TimeStampMillis:=this.pData[ArrSize][3]!=""
}
; Добавление временной метки массиву без неё
if !this.TimeStampExist[this.Proc]
{
if (ArrSize>this.prevArrSize[this.Proc] and ArrSize)
{
tmp2:=this.StampT[this.Proc][this.prevArrSize[this.Proc]]
tmp3:=this.TimeSub([A_Now,A_MSec],tmp2)
tmp1:=ArrSize-this.prevArrSize[this.Proc]
tmp3:=tmp3//tmp1
if (tmp3=0)
tmp3:=1
loop tmp1
{
add:=a_index*tmp3
this.StampT[this.Proc].Push(this.TimeAddMs(tmp2,add))
}
this.prevArrSize[this.Proc]:=ArrSize
}
}
Period:=this.GPosW/this.ZoomX ; количество пикселей на точку по X
PerioT:=this.GPosW/this.ZoomT ; количество пикселей на миллисекунду по X
this.PerioT:=PerioT
if this.YScale[this.Proc]
Pixel:=this.GPosH/this.YScale[this.Proc] ; сколько пикселей занимает 1 единица по Y
else
Pixel:=1
ZeroPos:=this.ZeroPosU
; Пауза скролинга для режима отображения по точкам
if (this.Pause and this.Proc=this.Sel and this.prev_ArrSize[this.Proc] and ArrSize!=this.prev_ArrSize[this.Proc])
{
tmp1:=ArrSize-this.prev_ArrSize[this.Proc]
this.X_Offset+=tmp1
this.OldX_Offset+=tmp1
}
this.prev_ArrSize[this.Proc]:=ArrSize
; Перемещение графика
L_Button:
if (MouseIn and mY<this.GPosH and getkeystate("LButton","P") and !this.Setting)
{
if !this.GetmCoordOnce
{
this.LButtonStart:=a_tickcount
this.Old_mX:=mX
this.Old_mY:=mY
this.OldX_Offset:=this.X_Offset
this.OldXTOffset:=this.XTOffset
this.GetmCoordOnce:=true
this.OffsetSetting:=true
this.ShiftStrt:=true
}
this.X_Offset:=this.OldX_Offset-round((this.Old_mX-mX)/Period)
this.XTOffset:=this.OldXTOffset-round((this.Old_mX-mX)/PerioT)
DeltaY:=this.Old_mY-mY
if (this.Sel=this.Proc)
this.ZeroPos+=DeltaY
if (this.Sel=this.Proc)
this.Old_mY:=mY
if (this.OldX_Offset-this.X_Offset!=0)
this.MouseMoved:=true
}
else if (this.GetmCoordOnce and !getkeystate("LButton","P"))
{
this.OffsetSetting:=false
; Добавление координаты маркеру
if !this.MouseMoved
this.XMarker[1]:=mX
this.MouseMoved:=false
this.GetmCoordOnce:=false
}
if !getkeystate("LButton","P")
this.SearchStop[this.Proc]:=false
; Выделение участка
R_Button:
if (MouseIn and mY<this.GPosH and getkeystate("RButton","P") and !this.Setting)
{
if !this.GetStartPosRectOnce
{
this.GetStartPosRectOnce:=true
this.RectXs:=mX
this.RectYs:=mY
}
if (this.RectXs>mX)
this.RectX:=mX
else
this.RectX:=this.RectXs
if (this.RectYs>mY)
this.RectY:=mY
else
this.RectY:=this.RectYs
this.RectW:=abs(this.RectXs-mX)
this.RectH:=abs(this.RectYs-mY)
if (this.RectW>10 and this.RectH>10)
this.DrawRectangle(this.Font_Colour,this.RectX,this.RectY,this.RectW,this.RectH)
else
this.DrawRectangle(this.GrayPen2,this.RectX,this.RectY,this.RectW,this.RectH)
}
else if (this.GetStartPosRectOnce and !getkeystate("RButton","P"))
{
this.GetStartPosRectOnce:=false
if (this.RectW>10 and this.RectH>10)
{
this.RectZoom:=true
this.SaveZoomX:=this.ZoomX
this.SaveZoomT:=this.ZoomT
this.SaveX_Offset:=this.X_Offset
this.SaveXTOffset:=this.XTOffset
this.SavePause:=this.Pause
this.Pause:=true
this.ShiftStrt:=true
loop Ars
{
this.SaveAutoScale[a_index]:=this.AutoScale[a_index]
this.SaveZeroPos:=this.ZeroPos
this.SaveYScale[a_index]:=this.YScale[a_index]
if this.AutoScale[a_index]
{
this.AutoScale[a_index]:=false
}
P:=this.GPosH/this.YScale[a_index] ; сколько пикселей занимает 1 единица по Y
this.YScale[a_index]:=this.RectH/P
}
this.UpdateMenu()
U:=this.SaveYScale[this.Sel]/this.GPosH ; сколько единиц занимает 1 пиксель по Y
P:=this.GPosH/this.YScale[this.Sel] ; сколько пикселей занимает 1 единица по Y
RectY2:=(this.RectY+this.RectH)
this.ZeroPos-=((this.ZeroPosU-RectY2)*U)*P+(this.GPosH-this.ZeroPosU)
this.ZeroPos:=round(this.ZeroPos)
if !this.ScaleXByTime
{
this.ZoomX:=round(this.RectW/Period)+1
this.X_Offset+=round((this.GPosW-(this.RectX+this.RectW))/Period)
}
else
{
this.ZoomT:=round(this.RectW/PerioT)
this.XTOffset+=round((this.GPosW-(this.RectX+this.RectW))/PerioT)
}
}
else if this.RectZoom
{
this.RectZoom:=false
this.ZoomX:=this.SaveZoomX
this.ZoomT:=this.SaveZoomT
this.X_Offset:=this.SaveX_Offset
this.XTOffset:=this.SaveXTOffset
this.Pause:=this.SavePause
this.ShiftStrt:=true
this.ZeroPos:=this.SaveZeroPos
loop Ars
{
this.YScale[a_index]:=this.SaveYScale[a_index]
if ((this.SaveAutoScale[a_index] and !this.AutoScale[a_index]) or (!this.SaveAutoScale[a_index] and this.AutoScale[a_index]))
{
this.AutoScale[a_index]:=true
this.UpdateMenu()
}
}
}
}
; Обработать колесо мыши
Whell:
if (MouseIn and (Graph.WheelUp or Graph.WheelDown) and Graph.HotKeymW=this.GuiGraph.Hwnd and this.Proc=1)
{
CoefHi:=mY/this.GPosH
CoefLo:=(this.GPosH-mY)/this.GPosH
tmp1:=round(this.ZoomX/3)+1
tmt1:=round(this.ZoomT/3)+1
if Graph.WheelUp
{
this.ZoomX-=tmp1
this.ZoomT-=tmt1
}
else if Graph.WheelDown
{
this.ZoomX+=tmp1
this.ZoomT+=tmt1
}
Graph.WheelUp:=false
Graph.WheelDown:=false
if (this.ZoomX<10)
this.ZoomX:=10
if (this.ZoomX>100000)
this.ZoomX:=100000
if (this.ZoomT<1000)
this.ZoomT:=1000
if (this.ZoomT>Graph.MaxTime)
this.ZoomT:=Graph.MaxTime
this.ShiftStrt:=true
this.Pause:=true
tmp1:=(this.GPosW-mX)/Period
tmp2:=(this.GPosW-mX)/(this.GPosW/this.ZoomX)
this.X_Offset+=round(tmp1-tmp2)
tmp1:=(this.GPosW-mX)/PerioT
tmp2:=(this.GPosW-mX)/(this.GPosW/this.ZoomT)
this.XTOffset+=round(tmp1-tmp2)
}
; ограничить перемещение графика
if (this.Proc=this.Sel)
{
if !this.ScaleXByTime
{
tmp1:=this.ZoomX//2
if (this.X_Offset<-tmp1)
this.X_Offset:=-tmp1
else if (this.X_Offset>0 and this.X_Offset>this.ArrSize[this.Proc]-tmp1)
this.X_Offset:=this.ArrSize[this.Proc]-tmp1
}
else
{
tmp1:=this.ZoomT//2
if this.TimeStampExist[this.Proc]
{
if this.TimeStampMillis
{
tmp2:=this.TimeSub([A_Now,A_MSec],[this.pData[this.pData.Length][2],this.pData[this.pData.Length][3]])
tmp3:=this.TimeSub([A_Now,A_MSec],[this.pData[1][2],this.pData[1][3]])
}
else
{
tmp2:=this.TimeSub([A_Now,A_MSec],[this.pData[this.pData.Length][2],0])
tmp3:=this.TimeSub([A_Now,A_MSec],[this.pData[1][2],0])
}
}
else
{
tmp2:=this.TimeSub([A_Now,A_MSec],[this.StampT[this.Proc][this.StampT[this.Proc].Length][1],this.StampT[this.Proc][this.StampT[this.Proc].Length][2]])
tmp3:=this.TimeSub([A_Now,A_MSec],[this.StampT[this.Proc][1][1],this.StampT[this.Proc][1][2]])
}
tmp2-=tmp1
tmp3-=tmp1
if (this.XTOffset<-tmp1)
{
this.XTOffset:=-tmp1
this.ShiftStrt:=true
}
else if (this.XTOffset<tmp2)
{
this.XTOffset:=tmp2
this.ShiftStrt:=true
}
else if (this.XTOffset>0 and this.XTOffset>tmp3)
{
this.XTOffset:=tmp3
this.ShiftStrt:=true
}
; this.XTOffset:=Integer(this.XTOffset)
}
}
; отрисовать сетку
if (this.Sel=this.Proc)
{
tmpc:=this.AHSVToARGB(200,this.Hue[this.Proc],this.Hue[this.Proc]>255?0:100,this.Hue[this.Proc]>255?(this.Hue[this.Proc]>>8):255)
LineH:=this.Pos.H*2
RoundTo:=1
GoAgain:
Drawed:=0
if (ZeroPos<=this.GPosH+1 and ZeroPos>=0)
{
loop ZeroPos//LineH
{
tmp1:=a_index*LineH
tmp2:=tmp1/Pixel
Val:=round(tmp2,-(strlen(round(tmp2))-RoundTo))
if (Val=0)
continue
CoordY:=ZeroPos-Val*Pixel
if (CoordY<0)
break
this.DrawString(" " Val,0,CoordY,,,,this.Font_Colour,tmpc)
this.DrawLine(this.GrayPen2,0,CoordY,this.GPosW,CoordY)
}
loop (this.GPosH-ZeroPos)//LineH
{
tmp1:=a_index*LineH
tmp2:=tmp1/Pixel
Val:=round(tmp2,-(strlen(round(tmp2))-RoundTo))
if (Val=0)
continue
CoordY:=ZeroPos+Val*Pixel
if (CoordY>this.GPosH)
break
this.DrawString("-" Val,0,CoordY-this.Pos.H,,,,this.Font_Colour,tmpc)
this.DrawLine(this.GrayPen2,0,CoordY,this.GPosW,CoordY)
}
}
else if (ZeroPos>this.GPosH)
{
loop this.GPosH//LineH
{
tmp1:=ZeroPos-a_index*LineH
tmp2:=tmp1/Pixel
Val:=round(tmp2,-(strlen(round(tmp2))-RoundTo))
CoordY:=ZeroPos-Val*Pixel
if (prevCoordY!=CoordY and CoordY<=this.GPosH-this.Pos.H and CoordY>=0)
{
this.DrawString(" " Val,0,CoordY,,,,this.Font_Colour,tmpc)
this.DrawLine(this.GrayPen2,0,CoordY,this.GPosW,CoordY)
Drawed++
}
prevCoordY:=CoordY
}
if (Drawed<1)
{
RoundTo++
if (RoundTo<10)
goto GoAgain
tmp1:=ZeroPos-this.GPosH/2
tmp2:=tmp1/Pixel
Val:=round(tmp2)
CoordY:=ZeroPos-Val*Pixel
this.DrawString(" " Val,0,CoordY,,,,this.Font_Colour,tmpc)
this.DrawLine(this.GrayPen2,0,CoordY,this.GPosW,CoordY)
}
}
else if (ZeroPos<0)
{
loop this.GPosH//LineH
{
tmp1:=-ZeroPos+a_index*LineH
tmp2:=tmp1/Pixel
Val:=round(tmp2,-(strlen(round(tmp2))-RoundTo))
CoordY:=ZeroPos+Val*Pixel
if (prevCoordY!=CoordY and CoordY<=this.GPosH+1 and CoordY>=this.Pos.H)
{
this.DrawString("-" Val,0,CoordY-this.Pos.H,,,,this.Font_Colour,tmpc)
this.DrawLine(this.GrayPen2,0,CoordY,this.GPosW,CoordY)
Drawed++
}
prevCoordY:=CoordY
}
if (Drawed<1)
{
RoundTo++
if (RoundTo<10)
goto GoAgain
tmp1:=-ZeroPos+this.GPosH/2
tmp2:=tmp1/Pixel
Val:=round(tmp2)
CoordY:=ZeroPos+Val*Pixel
this.DrawString("-" Val,0,CoordY-this.Pos.H,,,,this.Font_Colour,tmpc)
this.DrawLine(this.GrayPen2,0,CoordY,this.GPosW,CoordY)
}
}
; отрисовать линию и текст нуля
if (ZeroPos<=this.GPosH+1 and ZeroPos>=0)
{
this.DrawLine(this.GrayPen,0,ZeroPos,this.GPosW,ZeroPos)
tmp0:=ZeroPos+this.Pos.H//2
tmp1:=(this.GPosH>tmp0) ? ZeroPos-this.Pos.H//2 : this.GPosH-this.Pos.H
this.DrawString("0",0,tmp1,,,,this.Font_Colour,tmpc)
}
}
; сетка отрисована
if (!ArrSize and this.Proc=this.Sel)
this.MessagePos:=this.DrawString("Нет данных",this.GPosW//2-this.MessagePos.W//2,this.GPosH//2-this.MessagePos.H//2,,,,this.Font_Colour,this.Font_Back)
if (this.SearchSkip[this.Proc]>0)
this.SearchSkip[this.Proc]--
; Отрисовка графика ----------------------------------------------------------------
hi_lim:=Graph.min
lo_lim:=Graph.max
; Oldi:=1
NotScaleXByTime:
this.LockYP[this.Proc]:=0
this.LockYM[this.Proc]:=0
StampLine:=this.StampPos.W/2
this.Val_UnderGraph_Drawed[this.Proc]:=false
if (!this.ScaleXByTime and ArrSize)
{
Old_CoordY:=ZeroPos
Old_CoordX:=this.GPosW+10
GPoints:=[[Old_CoordX,Old_CoordY]]
Aindex:=0
Oldi:=ArrSize
if !this.GHide[this.Proc]
loop this.GPosW
{
iLast:=a_index=this.GPosW
i:=Floor(ArrSize-(a_index/Period+1))-this.X_Offset
if (i>ArrSize and !iLast)
continue
if (i<1)
i:=1
if iLast
{
if (i-1>0)
i--
else
i:=Oldi
if (i+1>ArrSize)
continue
}
Aindex++
if (Aindex=1 and i+1<=ArrSize and i>0)
{
if !this.TimeStampExist[this.Proc]
Value:=this.pData[i]
else
Value:=this.pData[i][1]
tmp1:=Value?Value:0
Value:=Value!=""?Value:"Null"
if (tmp1!="")
{
hi_lim:=tmp1>hi_lim ? tmp1 : hi_lim
lo_lim:=tmp1<lo_lim ? tmp1 : lo_lim
}
CoordY:=ZeroPos-tmp1*Pixel
if (CoordY<-1)
CoordY:=0
else if (CoordY>this.GPosH+1)
CoordY:=this.GPosH
GPoints.Push([this.GPosW,CoordY])
}
if !this.TimeStampExist[this.Proc]
Value:=this.pData[i]
else
Value:=this.pData[i][1]
tmp1:=Value?Value:0
Value:=Value!=""?Value:"Null"
if (tmp1!="")
{
hi_lim:=tmp1>hi_lim ? tmp1 : hi_lim
lo_lim:=tmp1<lo_lim ? tmp1 : lo_lim
}
CoordX:=this.GPosW-a_index
CoordY:=ZeroPos-tmp1*Pixel
SkipLine:=false
if (CoordY<-1)
{
CoordY:=0
SkipLine:=true
this.LockYP[this.Proc]++
}
else if (CoordY>this.GPosH+1)
{
CoordY:=this.GPosH
SkipLine:=true
this.LockYM[this.Proc]++
}
NewStamp:=false
NewXMarker:=false
if (Oldi!=i)
{
; линия графика
if !this.Smooth[this.Proc]
{
GPoints.Push([Old_CoordX,CoordY])
Old_CoordY:=CoordY
}
GPoints.Push([CoordX,CoordY])
; Отрисовка подробностей при малом увеличении
if (Oldi-i>1 and !this.TimeOut)
{
max:=Graph.min
min:=Graph.max
loop Oldi-i+1
{
j:=i+a_index-1
if (j<1 or j>ArrSize)
continue
if !this.TimeStampExist[this.Proc]
tmp1:=this.pData[j]
else
tmp1:=this.pData[j][1]
min:=min<tmp1?min:tmp1
max:=max>tmp1?max:tmp1
if (tmp1!="")
{
hi_lim:=tmp1>hi_lim ? tmp1 : hi_lim
lo_lim:=tmp1<lo_lim ? tmp1 : lo_lim
}
}
min:=ZeroPos-min*Pixel
max:=ZeroPos-max*Pixel
if (min<0)
min:=1
if (min>this.GPosH)
min:=this.GPosH
if (max<0)
max:=0
if (max>this.GPosH)
max:=this.GPosH-1
GPoints.Push([CoordX,min])
GPoints.Push([CoordX,max])
GPoints.Push([CoordX,CoordY])
}
; Дорисовать точки при большом увеличении
if (Old_CoordX-CoordX>3)
this.DrawEllipse(this.Pen[this.Proc],CoordX-1,CoordY-1,2,2,this.LineW[this.Proc])
; текст значения под курсором
if (!this.Val_UnderGraph_Drawed[this.Proc] and MouseIn)
if (mX>=CoordX and mX<=CoordX+20)
if (mY>CoordY and mY<CoordY+20)
{
this.Val_UnderGraph_Drawed[this.Proc]:=true
this.UnderGX[this.Proc]:=CoordX
this.UnderGY[this.Proc]:=CoordY
this.UnderGV[this.Proc]:=Value
}
Old_CoordX:=CoordX
Old_CoordY:=CoordY
Oldi:=i
NewStamp:=true
if (this.Sel=this.Proc)
NewXMarker:=true
}
; линия и текст временой шкалы
if (this.Sel=this.Proc)
{
if Period>=1
StampLine++
else
StampLine+=1
tmp1:=this.StampPos.W+2
if (NewStamp and StampLine>tmp1) or (!Stamp and a_index=this.GPosW)
{
StampLine:=0
Stamp:=true
this.DrawLine(this.GrayPen2,CoordX,0,CoordX,this.GPosH)
if !this.TimeStampExist[this.Proc]
{
tmp10:=FormatTime(this.StampT[this.Proc][i][1],"HH:mm:ss")
tmp10.="`n" format("{:03}",this.StampT[this.Proc][i][2]) "ms"
}
else
{
tmp10:=FormatTime(this.pData[i][2],"dd.MM.yyyy'`n'HH:mm:ss")
if (this.TimeStampMillis and this.pData[i][3]!="")
tmp10.="." format("{:03}",this.pData[i][3])
}
StampPos:=this.DrawString(tmp10,CoordX-this.StampPos.W/2,this.GPosH,,,,this.Font_Colour,this.GrayPen2)
if !GetSizeOnce
{
GetSizeOnce:=true
this.StampPos:=StampPos
this.StampOffset:=this.StampPos.H
}
if (prevStampPos.w)
{
if (this.StampPos.X+this.StampPos.w>prevStampPos.X)
this.StampsNum--
if (this.StampPos.X+this.StampPos.w*2+5<prevStampPos.X)
this.StampsNum++
if this.StampsNum<2
this.StampsNum:=2
}
prevStampPos:=this.StampPos
}
; маркеры
tmp1:=this.GPosW-a_index
loop 2
{
if (NewXMarker and !XMarker[a_index] and tmp1<this.XMarker[a_index])
{
XMarker[a_index]:=true
XMarkeri[a_index]:=i
XMarkerCoord[a_index]:=tmp1
}
}
NewXMarker:=false
}
}
; рисовать линию графика
if !this.GHide[this.Proc]
this.DrawLines(this.Pen[this.Proc],GPoints,this.LineW[this.Proc])
; блокировать перемещение по Y
this.LockYP[this.Proc]:=(this.LockYP[this.Proc]>=Aindex-3)?1:0
this.LockYM[this.Proc]:=(this.LockYM[this.Proc]>=Aindex-3)?1:0
}
ScaleXByTime:
if (this.ScaleXByTime and ArrSize)
{
Strt:=this.TimeSubMs([A_Now,A_MSec],this.XTOffset)
if (this.Pause and (!this.SaveStrt[1] or this.OffsetSetting or this.ShiftStrt))
{
this.SaveStrt:=Strt
this.ShiftStrt:=false
}
else if (!this.Pause and this.SaveStrt[1])
this.SaveStrt:=[0,0]
if this.Pause
Strt:=this.SaveStrt
Endt:=this.TimeSubMs(Strt,this.ZoomT)
; линия и текст временой шкалы
if (this.Sel=this.Proc)
{
loop this.GPosW
{
CoordX:=this.GPosW-(a_index-1)
StampLine++
tmp1:=this.StampPos.W+2
if (StampLine>tmp1) or (!Stamp and a_index=this.GPosW)
{
Stamp:=true
StampLine:=0
this.DrawLine(this.GrayPen2,CoordX,0,CoordX,this.GPosH)
tmp2:=(this.ZoomT/this.GPosW)*(a_index-1)
tmp1:=this.TimeSubMs(Strt,tmp2)
tmp10:=FormatTime(tmp1[1],"dd.MM.yyyy'`n'HH:mm:ss")
tmp10.="." tmp1[2]
StampPos:=this.DrawString(tmp10,CoordX-this.StampPos.W/2,this.GPosH,,,,this.Font_Colour,this.GrayPen2)
if !GetSizeOnce
{
GetSizeOnce:=true
this.StampPos:=StampPos
this.StampOffset:=this.StampPos.H
}
if (prevStampPos.w)
{
if (this.StampPos.X+this.StampPos.w>prevStampPos.X)
this.StampsNum--
if (this.StampPos.X+this.StampPos.w*2+5<prevStampPos.X)
this.StampsNum++
if this.StampsNum<2
this.StampsNum:=2
}
prevStampPos:=this.StampPos
}
}
}
; найти первую точку
iStart:=1
Same:=0
if !this.GHide[this.Proc]
loop ArrSize
{
i:=ArrSize-(a_index-1)-this.SearchSkip[this.Proc]
if (i<1)
{
iStart:=1
break
}
if !this.TimeStampExist[this.Proc]
{
iTime:=this.StampT[this.Proc][i][1]
iTimeMs:=this.StampT[this.Proc][i][2]
if (iTime>Strt[1] or (iTime=Strt[1] and iTimeMs>=Strt[2]))
continue
else
{
iStart:=i=ArrSize?i:i+1
break
}
}
else
{
iTime:=this.pData[i][2]
if this.TimeStampMillis
iTimeMs:=this.pData[i][3]
else
{
if !Same
{
iTimeMs:=0
loop 1000
{
j:=1+i-a_index
if (j>0 and iTime=this.pData[j][2])
Same++
else
break
}
SameT:=1000/(Same+1)
}
if (Same>0)
{
iTimeMs:=round(SameT*Same)
Same--
}
}
if (iTime>Strt[1] or (this.TimeStampMillis and iTime=Strt[1] and iTimeMs>=Strt[2]))
continue
else
{
iStart:=i=ArrSize?i:i+1
break
}
}
}
Old_CoordY:=ZeroPos
Old_CoordX:=this.GPosW+10
GPoints:=[[Old_CoordX,Old_CoordY]]
SearchSkip:=this.SearchSkip[this.Proc]?this.SearchSkip[this.Proc]:0
Same:=0
Aindex:=0
Oldi:=iStart
iLast:=false
if !this.GHide[this.Proc]
while !iLast ;loop iStart
{
i:=iStart-(a_index-1)
if (i<1)
{
i:=1
iLast:=true
}
if !this.TimeStampExist[this.Proc]
{
iTime:=this.StampT[this.Proc][i][1]
iTimeMs:=this.StampT[this.Proc][i][2]
}
else
{
iTime:=this.pData[i][2]
if this.TimeStampMillis
iTimeMs:=this.pData[i][3]
else
{
if !Same
{
iTimeMs:=0
loop 1000
{
j:=i-a_index
if (j>0 and iTime=this.pData[j][2])
Same++
else
break
}
SameT:=1000/(Same+1)
}
if (Same>0)
{
iTimeMs:=round(SameT*Same)
Same--
}
}
}
if (iTime<Endt[1])
iLast:=true
mms:=Strt[2]-iTimeMs
if (mms<0)
{
mms+=1000
iTime:=DateAdd(iTime,1,"Seconds")
}
ttt:=DateDiff(Strt[1],iTime,"Seconds")
CoordX:=this.GPosW-round(PerioT*(ttt*1000+mms))
Aindex++
if (Aindex=1 and !this.SearchStop[this.Proc])
{
tmp1:=ArrSize-i
if (SearchSkip<tmp1)
SearchSkip:=tmp1
}
if (CoordX!=Old_CoordX or iLast)
{
if !this.TimeStampExist[this.Proc]
Value:=this.pData[i]
else
Value:=this.pData[i][1]
tmp1:=Value?Value:0
if (Value!="" and Aindex)
{
hi_lim:=Value>hi_lim ? Value : hi_lim
lo_lim:=Value<lo_lim ? Value : lo_lim
}
Value:=Value!=""?Value:"Null"
CoordY:=ZeroPos-tmp1*Pixel
SkipLine:=false
if (CoordY<-1)
{
CoordY:=0
SkipLine:=true
this.LockYP[this.Proc]++
}
else if (CoordY>this.GPosH+1)
{
CoordY:=this.GPosH
SkipLine:=true
this.LockYM[this.Proc]++
}
; линия графика
if !this.Smooth[this.Proc]
{
GPoints.Push([Old_CoordX,CoordY])
Old_CoordY:=CoordY
}
GPoints.Push([CoordX,CoordY])
; Отрисовка подробностей при малом увеличении
if (Oldi-i>1 and !this.TimeOut)
{
max:=Graph.min
min:=Graph.max
loop Oldi-i
{
j:=i+a_index-1
if (j<1 or j>ArrSize)
continue
if !this.TimeStampExist[this.Proc]
tmp1:=this.pData[j]
else
tmp1:=this.pData[j][1]
min:=min<tmp1?min:tmp1
max:=max>tmp1?max:tmp1
if (tmp1!="")
{
hi_lim:=tmp1>hi_lim ? tmp1 : hi_lim
lo_lim:=tmp1<lo_lim ? tmp1 : lo_lim
}
}
min:=ZeroPos-min*Pixel
max:=ZeroPos-max*Pixel
if (min<0)
min:=1
if (min>this.GPosH)
min:=this.GPosH
if (max<0)
max:=0
if (max>this.GPosH)
max:=this.GPosH-1
GPoints.Push([CoordX,min])
GPoints.Push([CoordX,max])
GPoints.Push([CoordX,CoordY])
}
; Дорисовать точки при большом увеличении
if (Old_CoordX-CoordX>3)
this.DrawEllipse(this.Pen[this.Proc],CoordX-1,CoordY-1,2,2,this.LineW[this.Proc])
; текст значения под курсором
if (!this.Val_UnderGraph_Drawed[this.Proc] and MouseIn)
if (mX>=CoordX and mX<=CoordX+20)
if (mY>CoordY and mY<CoordY+20)
{
this.Val_UnderGraph_Drawed[this.Proc]:=true
this.UnderGX[this.Proc]:=CoordX
this.UnderGY[this.Proc]:=CoordY
this.UnderGV[this.Proc]:=Value
}
Old_CoordX:=CoordX
Old_CoordY:=CoordY
Oldi:=i
if iLast
break
; маркеры
if (this.Sel=this.Proc)
{
loop 2
{
if (!XMarker[a_index] and CoordX<this.XMarker[a_index])
{
XMarker[a_index]:=true
XMarkeri[a_index]:=i
if !this.TimeStampMillis
MarkerTimeMs[a_index]:=format("{:03}",iTimeMs)
XMarkerCoord[a_index]:=CoordX
}
}
}
}
}
; рисовать линию графика
if !this.GHide[this.Proc]
this.DrawLines(this.Pen[this.Proc],GPoints,this.LineW[this.Proc])
this.ZoomX:=Aindex?Aindex:1
this.SearchSkip[this.Proc]:=SearchSkip
; блокировать перемещение по Y
this.LockYP[this.Proc]:=(this.LockYP[this.Proc]>=Aindex-3)?1:0
this.LockYM[this.Proc]:=(this.LockYM[this.Proc]>=Aindex-3)?1:0
}
; Автомасштаб
if (this.AutoScale[this.Proc] and !this.GHide[this.Proc] and (!this.OScale or this.Proc=this.Sel))
{
tmp1:=this.GPosH//2
if (this.ZeroPosU>tmp1 and this.ZeroPosU<this.GPosH+1)
{
if (hi_lim>0)
this.YScale[this.Proc]:=abs(hi_lim)+(this.GPosH-this.ZeroPosU+10)/Pixel
else
this.YScale[this.Proc]:=-lo_lim+(this.ZeroPosU+10)/Pixel
}
else if (this.ZeroPosU<=tmp1 and this.ZeroPosU>0)
{
if (lo_lim<0)
this.YScale[this.Proc]:=-lo_lim+(this.ZeroPosU+10)/Pixel
else
this.YScale[this.Proc]:=abs(hi_lim)+(this.GPosH-this.ZeroPosU+10)/Pixel
}
if (this.YScale[this.Proc]=0)
this.YScale[this.Proc]:=1
}
this.DrawLine(this.GrayPen2,0,this.GPosH,this.GPosW,this.GPosH)
this.DrawLine(this.GrayPen2,0,this.GPosH+StampPos.H,this.GPosW,this.GPosH+StampPos.H)
; текст значения под курсором
if this.Val_UnderGraph_Drawed[this.Proc]
{
this.DrawEllipse(0xffffffff,this.UnderGX[this.Proc]-3,this.UnderGY[this.Proc]-3,6,6,this.LineW[this.Proc])
this.DrawEllipse(0xff000000,this.UnderGX[this.Proc]-2,this.UnderGY[this.Proc]-2,4,4,this.LineW[this.Proc])
this.DrawEllipse(0xffffffff,this.UnderGX[this.Proc]-1,this.UnderGY[this.Proc]-1,2,2,this.LineW[this.Proc])
tmpX:=this.UnderGX[this.Proc]+(5<this.GPosW-this.ValTipPos.W)?this.UnderGX[this.Proc]+5:this.GPosW-this.ValTipPos.W
tmpY:=(this.UnderGY[this.Proc]-this.Pos.H<0)?0:(this.UnderGY[this.Proc]-this.Pos.H-5)
if (tmpY-PrevtmpY<this.ValTipPos.H)
{
if (mY>this.GPosH//2)
tmpY:=PrevtmpY-this.ValTipPos.H
else
{
tmpY:=PrevtmpY+this.ValTipPos.H
tmpX+=8
}
}
tmpC:=this.AHSVToARGB(200,this.Hue[this.Proc],this.Hue[this.Proc]>255?0:100,this.Hue[this.Proc]>255?(this.Hue[this.Proc]>>8):255)
this.ValTipPos:=this.DrawString((IsInteger(this.UnderGV[this.Proc])?this.UnderGV[this.Proc]:Format("{:0." this.FloatFormat "f}",this.UnderGV[this.Proc])) " " this.ArrName[this.Proc],tmpX,tmpY,,,,this.Font_Colour,tmpC)
PrevtmpY:=tmpY
}
if (this.ShowMarkers and this.Sel=this.Proc)
{
if (XMarkerCoord[1] or XMarkerCoord[2])
{
MarkerText[1]:=(this.ArrName[this.Proc]!=""?this.ArrName[this.Proc]:"Линия №" this.Proc) " Точек = " abs(XMarkeri[1]-XMarkeri[2])+1 "`nВремя "
if this.TimeStampExist[this.Proc]
loop 11
MarkerText[1].=" "
MarkerText[1].="Значение`n"
}
loop 2
{
if XMarkerCoord[a_index]
{
if !this.TimeStampExist[this.Proc]
{
MarkerTime[a_index]:=this.StampT[this.Proc][XMarkeri[a_index]][1]
MarkerTimeMs[a_index]:=this.StampT[this.Proc][XMarkeri[a_index]][2]
tmp10:=FormatTime(MarkerTime[a_index],"HH:mm:ss") "." MarkerTimeMs[a_index]
MarkerValue[a_index]:=this.pData[XMarkeri[a_index]]
MarkerText[a_index].=tmp10 " " Format("{:0." this.FloatFormat "f}",MarkerValue[a_index])
}
else
{
MarkerTime[a_index]:=this.pData[XMarkeri[a_index]][2]
if (this.TimeStampMillis and this.pData[XMarkeri[a_index]][3]!="")
MarkerTimeMs[a_index]:=this.pData[XMarkeri[a_index]][3]
tmp10:=FormatTime(MarkerTime[a_index],"dd.MM.yyyy HH:mm:ss") "." MarkerTimeMs[a_index]
MarkerValue[a_index]:=this.pData[XMarkeri[a_index]][1]
MarkerText[a_index].=tmp10 " " Format("{:0." this.FloatFormat "f}",this.pData[XMarkeri[a_index]][1])
}
}
}
if (XMarkerCoord[1] and XMarkerCoord[2])
{
i:=1, j:=2
if (XMarkerCoord[1]<XMarkerCoord[2])
i:=2, j:=1
ms:=MarkerTimeMs[i]-MarkerTimeMs[j]
if (ms<0)
MarkerTime[j]:=DateAdd(MarkerTime[j],1,"Seconds")
MarkerDeltaT:=DateDiff(MarkerTime[i],MarkerTime[j],"Seconds")
MarkerDeltaT:=DateAdd(1601,MarkerDeltaT,"Seconds")
Y:=FormatTime(MarkerDeltaT,"yyyy")
M:=FormatTime(MarkerDeltaT,"MM")
D:=FormatTime(MarkerDeltaT,"dd")
Y:=format("{:04}",Y-1601)
M:=format("{:02}",M-1)
D:=format("{:02}",D-1)
if this.TimeStampExist[this.Proc]
MarkerDText.=D "." M "." Y " "
tmp10:=FormatTime(MarkerDeltaT,"HH:mm:ss")
MarkerDText.=tmp10
if MarkerTimeMs[i]
MarkerDText.="." format("{:03}",abs(ms))
MarkerMax:=Graph.min
MarkerMin:=Graph.max
ValNum:=XMarkeri[i]-XMarkeri[j]+1
Summ:=0
loop ValNum
{
if !this.TimeStampExist[this.Proc]
Val:=this.pData[XMarkeri[j]+A_Index-1]
else
Val:=this.pData[XMarkeri[j]+A_Index-1][1]
Summ+=Val
if (Val>MarkerMax)
MarkerMax:=Val
if (Val<MarkerMin)
MarkerMin:=Val
}
MarkerMean:=Summ/ValNum
loop ValNum
{
if !this.TimeStampExist[this.Proc]
Val:=this.pData[XMarkeri[j]+A_Index-1]
else
Val:=this.pData[XMarkeri[j]+A_Index-1][1]
Deviation+=(Val-MarkerMean)**2
}
}
}
} ; Конец цикла
Loop________End:
; общий масштаб
if this.OScale
{
loop this.YScale.Length
{
if (a_index=this.Sel)
continue
this.YScale[a_index]:=this.YScale[this.Sel]
}
}
; Отрисовать меню
OnGraphMenu:
SelPos:=[]
tmpc:=this.AHSVToARGB(200,this.Hue[1],this.Hue[1]>255?0:100,this.Hue[1]>255?(this.Hue[1]>>8):255)
; первая строка (этой строки может не быть)
MenuSPY:=StampPos.Y+StampPos.H
if (Ars>1)
Pos:=this.DrawString("1",0,MenuSPY,,,"Center vCenter",this.GHide[1]?tmpc:this.Font_Colour,tmpc)
else
Pos:={X:0,Y:0,W:0,H:0,Chars:0,Lines:0}
SelPos.Push(Pos)
loop Ars
{
tmp1:=a_index+1
if (tmp1<=Ars)
{
tmpc:=this.AHSVToARGB(200,this.Hue[tmp1],this.Hue[tmp1]>255?0:100,this.Hue[tmp1]>255?(this.Hue[tmp1]>>8):255)
Pos:=this.DrawString(tmp1,SelPos[a_index].X+SelPos[a_index].W+5,MenuSPY,,,"Center vCenter",this.GHide[tmp1]?tmpc:this.Font_Colour,tmpc)
}
else
Pos:=this.DrawString("Выбран " this.Sel,SelPos[a_index].X+SelPos[a_index].W+5,MenuSPY,,,"Center vCenter",this.Font_Colour,this.LightBlueBrush)
SelPos.Push(Pos)
}
; вторая строка (первая)
MenuSPY:=StampPos.Y+StampPos.H+SelPos[1].H
if !this.ScaleXByTime
this.ZoomPos:=this.DrawString("Zoom X = " this.ZoomX " точек",0,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
else
{
tmp1:=this.MsToTime(this.ZoomT)
tmp1[1]-=1000000
tmp2:=FormatTime(tmp1[1],"dd HH:mm:ss")
tmp2.="." tmp1[2]
this.ZoomPos:=this.DrawString("Zoom X = " tmp2,0,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
}
this.SmoothPos:=this.DrawString(this.Smooth[this.Sel]?"~~~~":"_-_-",this.ZoomPos.W+this.Pos.W,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
this.TransPos:=this.DrawString("<" this.Transp[this.Sel] ">",this.SmoothPos.X+this.SmoothPos.W+this.Pos.W,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
this.LineWPos:=this.DrawString("[" this.LineW[this.Sel] "]",this.TransPos.X+this.TransPos.W+this.Pos.W,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
this.FontSizePos:=this.DrawString("Шрифт " this.FontSize,this.LineWPos.X+this.LineWPos.W+this.Pos.W,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
; третья строка (вторая)
MenuSPY+=this.ZoomPos.H
this.AutoPos:=this.DrawString("Авто",0,MenuSPY,,,"",this.AutoScale[this.Sel]?this.Font_Colour:this.GrayPen,this.LightBlueBrush)
this.ScalePos:=this.DrawString("Шкала " Format("{:0." this.FloatFormat "f}",this.YScale[this.Sel]),this.AutoPos.X+this.AutoPos.W,MenuSPY,,,"",this.Font_Colour,this.LightBlueBrush)
if ArAr
this.OScalePos:=this.DrawString(" общая",this.ScalePos.X+this.ScalePos.W,MenuSPY,,,"",this.OScale?this.Font_Colour:this.GrayPen,this.LightBlueBrush)
BWPos:=this.DrawString("(<<)",this.ScalePos.X+this.ScalePos.W+this.OScalePos.W+15,MenuSPY,,,"Center vCenter",this.Font_Colour,this.LightBlueBrush)
PWPos:=this.DrawString("(||)",BWPos.X+BWPos.W+2,MenuSPY,,,"Center vCenter",this.Font_Colour,this.LightBlueBrush)
FWPos:=this.DrawString("(>>)",PWPos.X+PWPos.W+2,MenuSPY,,,"Center vCenter",this.Font_Colour,this.LightBlueBrush)
; Размер меню
tmp1:=(this.AutoPos.H>this.ScalePos.H)?this.AutoPos.H:this.ScalePos.H
this.MenuOffset:=this.ZoomPos.H+tmp1+SelPos[1].H
; хитбоксы
SelHBA:=[]
SelHB:=0
SelSplitHB:=false
loop Ars
{
SelHBA.Push(this.HitBox(mX,mY,SelPos[a_index]))
if SelHBA[a_index]
{
SelHB:=a_index
break
}
}
if ArAr
SelSplitHB:=this.HitBox(mX,mY,SelPos[Ars+1])
LineWHB:=this.HitBox(mX,mY,this.LineWPos)
TransHB:=this.HitBox(mX,mY,this.TransPos)
FontSizeHB:=this.HitBox(mX,mY,this.FontSizePos)
ZoomHB:=this.HitBox(mX,mY,this.ZoomPos)
SmoothHB:=this.HitBox(mX,mY,this.SmoothPos)
AutoHB:=this.HitBox(mX,mY,this.AutoPos)
ScaleHB:=this.HitBox(mX,mY,this.ScalePos)
OScaleHB:=this.HitBox(mX,mY,this.OScalePos)
BWHB:=this.HitBox(mX,mY,BWPos)
PWHB:=this.HitBox(mX,mY,PWPos)
FWHB:=this.HitBox(mX,mY,FWPos)
HB:=AutoHB or ScaleHB or ZoomHB or SmoothHB or LineWHB or TransHB or FontSizeHB
or SelHB or OScaleHB or SelSplitHB or BWHB or PWHB or FWHB
if (MouseIn and HB and !this.OffsetSetting and !this.Setting and A_Cursor="Arrow")
{
this.Setting:=true
if AutoHB
{
TipText:="Автоматический масштаб вкл./выкл."
this.WhichSetting:=1
}
else if ScaleHB
{
TipText:="Масштаб шкалы`nЗажмите левую кн. мыши`n и потяните вверх/вниз`n или правой кнопкой мыши"
this.WhichSetting:=2
}
else if ZoomHB
{
TipText:="Масштаб по горизонтали`nЗажмите левую кн. мыши`n и потяните вверх/вниз`n или правой кнопкой мыши"
this.WhichSetting:=3
}
else if LineWHB
{
TipText:="Толщина линии графика`nЗажмите левую кн. мыши`n и потяните вверх/вниз`n или правой кнопкой мыши"
this.WhichSetting:=4
}
else if SelHB
{
TipText:="Нажмите левой кн. мыши чтобы`n выбрать график, настройки`n которого будут изменяться`nПравой кн. мыши - выключить график`n`n" this.ArrName[SelHB]
this.WhichSetting:=5
}
else if FontSizeHB
{
TipText:="Размер шрифта`nЗажмите левую кн. мыши`n и потяните вверх/вниз`n или правой кнопкой мыши"
this.WhichSetting:=6
}
else if SmoothHB
{
TipText:="Сглаживать ступеньки графика вкл./выкл."
this.WhichSetting:=7
}
else if OScaleHB
{
TipText:="Общий масштаб шкалы вкл./выкл."
this.WhichSetting:=8
}
else if SelSplitHB
{
TipText:="Нажмите чтобы отделить `nвыбранный график в отдельное окно`n`n" this.ArrName[this.Sel]
this.WhichSetting:=9
}
else if BWHB
{
TipText:="На 1 экран назад"
this.WhichSetting:=10
}
else if PWHB
{
TipText:="Пауза прокрутки"
this.WhichSetting:=11
}
else if FWHB
{
TipText:="На 1 экран вперед"
this.WhichSetting:=12
}
else if TransHB
{
TipText:="Видимость линии графика`nЗажмите левую кн. мыши`n и потяните вверх/вниз`n или правой кнопкой мыши"
this.WhichSetting:=13
}
this.TipPos:=this.DrawString(TipText,(this.GPosW-this.TipPos.W)//2,this.GPosH-this.TipPos.H,,,,this.Font_Colour,this.LightGreenBrush)
}
; Изменение настроек
if (getkeystate("LButton","P") and this.Setting)
{
if (this.WhichSetting=1)
{
this.AutoScale[this.Sel]:=!this.AutoScale[this.Sel]
if this.OScale
loop Ars
this.AutoScale[a_index]:=this.AutoScale[this.Sel]
this.WhichSetting:=0
}
else if (this.WhichSetting=2)
{
this.YScale[this.Sel]+=(round(abs(this.YScale[this.Sel])/20)+1)*DeltaY
this.YScale[this.Sel]:=round(this.YScale[this.Sel])
this.AutoScale[this.Sel]:=false
}
else if (this.WhichSetting=3)
{
this.ZoomX+=(round(abs(this.ZoomX)/20)+1)*DeltaY
this.ZoomX:=(this.ZoomX>100000)?100000:(this.ZoomX<10)?10:round(this.ZoomX)
this.ZoomT+=(round(abs(this.ZoomT)/20)+1)*DeltaY
this.ZoomT:=(this.ZoomT>Graph.MaxTime)?Graph.MaxTime:(this.ZoomT<1000)?1000:round(this.ZoomT)
}
else if (this.WhichSetting=4)
{
this.LineW[this.Sel]+=DeltaY/10
if (this.LineW[this.Sel]<1)
this.LineW[this.Sel]:=1
if (this.LineW[this.Sel]>5)
this.LineW[this.Sel]:=5
this.LineW[this.Sel]:=round(this.LineW[this.Sel],1)
}
else if (this.WhichSetting=5)
{
loop Ars
{
if (SelHBA[a_index])
{
this.Sel:=a_index
this.UpdateMenu()
break
}
}
this.WhichSetting:=0
}
else if (this.WhichSetting=6)
{
this.FontSize+=DeltaY
if (this.FontSize<8)
this.FontSize:=8
if (this.FontSize>70)
this.FontSize:=70
if (this.FontSize!=this.prevSize)
this.SetFont(,this.FontSize)
}
else if (this.WhichSetting=7)
{
this.Smooth[this.Sel]:=!this.Smooth[this.Sel]
this.WhichSetting:=0
}
else if (this.WhichSetting=8)
{
this.OScale:=!this.OScale
this.WhichSetting:=0
}
else if (this.WhichSetting=9)
{
this.GuiGraph.GetPos(&x,&y)
this.Child.Push(Graph())
this.Child[this.Child.Length].CreateTime:=this.CreateTime
this.Child[this.Child.Length].Show(x+20,y+20)
this.Parent++
this.Child[this.Child.Length].IsChild:=this.Parent
this.Child[this.Child.Length].DataArray:=this.Data[this.Sel]
this.Child[this.Child.Length].ArrName[1]:=this.ArrName[this.Sel]
this.Child[this.Child.Length].Parent:=this
ObjRelease(ObjPtr(this))
this.WhichSetting:=0
this.GHide[this.Sel]:=true
loop Ars
{
if !this.GHide[a_index]
this.Sel:=a_index
}
}
else if (this.WhichSetting=10)
{
if !this.ScaleXByTime
this.X_Offset+=this.ZoomX
else
this.XTOffset+=this.ZoomT
this.ShiftStrt:=true
this.WhichSetting:=0
}
else if (this.WhichSetting=11)
{
this.Pause:=!this.Pause
this.WhichSetting:=0
}
else if (this.WhichSetting=12)
{
if !this.ScaleXByTime
this.X_Offset-=this.ZoomX
else
this.XTOffset-=this.ZoomT
this.ShiftStrt:=true
this.WhichSetting:=0
}
else if (this.WhichSetting=13)
{
this.Transp[this.Sel]+=DeltaY
if (this.Transp[this.Sel]<1)
this.Transp[this.Sel]:=1
if (this.Transp[this.Sel]>255)
this.Transp[this.Sel]:=255
this.Pen[this.Sel]:=this.Transp[this.Sel]<<24|this.Pen[this.Sel]&0xffffff
}
}
if (getkeystate("RButton","P") and this.Setting)
{
if (this.WhichSetting=5)
{
loop Ars
{
if (SelHBA[a_index])
{
this.GHide[a_index]:=!this.GHide[a_index]
if this.GHide[a_index]
{
loop Ars
{
if !this.GHide[a_index]
this.Sel:=a_index
}
}
break
}
}
this.WhichSetting:=0
}
else if (this.WhichSetting=2)
{
this.WhichVal:="YScale"
this.GuiValText1.Value:="Масштаб шкалы"
this.GuiValVal.Value:=this.YScale[this.Sel]
this.GuiValText2.Value:=""
this.MenuVal()
this.WhichSetting:=0
}
else if (this.WhichSetting=3)
{
this.GuiValText1.Value:="Масштаб по горизонтали"
if this.ScaleXByTime
{
this.WhichVal:="ZoomT"
this.GuiValVal.Value:=this.ZoomT/60000
this.GuiValText2.Value:="минут"
}
else
{
this.WhichVal:="ZoomX"
this.GuiValVal.Value:=this.ZoomX
this.GuiValText2.Value:="точек"
}
this.MenuVal()
this.WhichSetting:=0
}
else if (this.WhichSetting=4)
{
this.WhichVal:="LineW"
this.GuiValText1.Value:="Толщина линии графика"
this.GuiValVal.Value:=this.LineW[this.Sel]
this.GuiValText2.Value:=""
this.MenuVal()
this.WhichSetting:=0
}
else if (this.WhichSetting=6)
{
this.WhichVal:="FontSize"
this.GuiValText1.Value:="Размер шрифта"
this.GuiValVal.Value:=this.FontSize
this.GuiValText2.Value:=""
this.MenuVal()
this.WhichSetting:=0
}
else if (this.WhichSetting=13)
{
this.WhichVal:="Transp"
this.GuiValText1.Value:="Видимость линии графика"
this.GuiValVal.Value:=this.Transp[this.Sel]
this.GuiValText2.Value:="0=прозрачен 255=видим"
this.MenuVal()
this.WhichSetting:=0
}
}
if (!getkeystate("LButton","P") and !getkeystate("RButton","P"))
{
this.Setting:=false
this.WhichSetting:=0
}
; Информация от маркеров
Markers:
max:=min:="`n"
if this.ShowMarkers
{
loop 2
{
if XMarkerCoord[a_index]
this.DrawLine(this.RedPen,XMarkerCoord[a_index],0,XMarkerCoord[a_index],this.GPosH)
}
if !XMarkerCoord[1]
MarkerText[1]:="Нажмите левой кн. мыши на график"
if !XMarkerCoord[2]
MarkerText[2]:="Нажмите правой кн. мыши на график"
if (XMarkerCoord[1] and XMarkerCoord[2])
{
StDeviation:=sqrt((Deviation/ValNum))
StDeviation:="Среднекв. отклонение = " Format("{:0." this.FloatFormat "f}",StDeviation)
MarkerMean:="Среднее = " Format("{:0." this.FloatFormat "f}",MarkerMean)
min:="Min = " Format("{:0." this.FloatFormat "f}",MarkerMin)
max:="Max = " Format("{:0." this.FloatFormat "f}",MarkerMax)
}
String:=MarkerText[1] "`n" MarkerText[2] "`n" MarkerDText "`n" MarkerMean "`n" StDeviation "`n" max "`n" min
Pos:=this.DrawString(String,0,this.AutoPos.Y+this.AutoPos.H,this.GPosW,,"",this.Font_Colour,this.LightGreenBrush)
}
; Подсказка о текущем увеличении
if ((!this.ScaleXByTime and this.OldZoomX!=this.ZoomX) or this.OldZoomT!=this.ZoomT)
{
this.ShowZoomTip:=1000
this.OldZoomX:=this.ZoomX
this.OldZoomT:=this.ZoomT
}
if (this.ShowZoomTip>0)
{
this.ShowZoomTip-=CycleTime
if !this.ScaleXByTime
this.iZoomPos:=this.DrawString("Zoom`n" this.ZoomX "`nточек",(this.GPosW-this.iZoomPos.W)//2,0,,,,this.Font_Colour,this.LightGreenBrush)
else
{
tmp1:=this.MsToTime(this.ZoomT)
tmp1[1]+=-1000000
tmp2:=FormatTime(tmp1[1],"dd HH:mm:ss")
tmp2.="." tmp1[2]
this.iZoomPos:=this.DrawString("Zoom`n" tmp2,(this.GPosW-this.iZoomPos.W)//2,0,,,,this.Font_Colour,this.LightGreenBrush)
}
}
; Подсказка о времени отрисовки
DllCall("QueryPerformanceCounter","Int64*",&EndTime:=0)
ElapsedTime:=round((EndTime-StartTime)/frequency*1000,1)
this.ETPos:=this.DrawString(ElapsedTime "ms",this.GPosW-this.ETPos.W,this.ZoomPos.Y+this.ETPos.H,,,,this.Font_Colour,this.Font_Back)
if (this.HitBox(mX,mY,this.ETPos) and MouseIn)
this.TipPos:=this.DrawString("Время отрисовки кадра",(this.GPosW-this.TipPos.W)//2,this.GPosH-this.TipPos.H,,,,this.Font_Colour,this.LightGreenBrush)
if !this.ScaleXByTime
{
if (ElapsedTime>1000)
{
if !this.TimeOut
{
this.TOZoomX:=this.ZoomX
this.TimeOut:=true
}
else
this.ZoomX-=round(abs(this.ZoomX)/10)
}
else if (this.TimeOut and this.ZoomX<this.TOZoomX or ElapsedTime<100)
{
this.TimeOut:=false
}
}
else
{
if (ElapsedTime>1000)
{
if !this.TimeOut
{
this.TOZoomT:=this.ZoomT
this.TimeOut:=true
}
else
this.ZoomT-=round(abs(this.ZoomT)/10)
}
else if (this.TimeOut and this.ZoomT<this.TOZoomT or ElapsedTime<100)
{
this.TimeOut:=false
}
}
; Обновить изображение
if !this.GuiHiden
this.Update()
this.OldmX:=mX
this.OldmY:=mY
this.Drawing:=false
ObjRelease(ObjPtr(this))
}
;||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/|||||||/||||
;|||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||||///|||
;||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////|||/////||
;|///////|///////|///////|///////|///////|///////|///////|///////|///////|///////|///////|///////|
;/////////////////////////////////////////////////////////////////////////////////////////////////
TimeSub(Time1,Time2)
{
T1:=Time1[1]
T2:=Time2[1]
ms:=Time1[2]-Time2[2]
if (ms<0)
{
ms+=1000
T2:=DateAdd(T2,1,"Seconds")
}
Dif:=DateDiff(T1,T2,"Seconds")
return Dif*1000+ms
}
TimeSubMs(Time,ValueMs)
{
if (ValueMs=0)
return Time
m:=0
if (ValueMs>0)
{
ms:=Time[2]-mod(ValueMs,1000)
if (ms<0)
{
ms+=1000
m:=1
}
t:=DateAdd(Time[1],-(Floor(ValueMs/1000)+m),"Seconds")
}
else
{
ms:=mod(-ValueMs,1000)+Time[2]
if (ms>999)
{
ms-=1000
m:=1
}
t:=DateAdd(Time[1],Floor(-ValueMs/1000)+m,"Seconds")
}
return [t,format("{:03}",round(ms))]
}
TimeAddMs(Time,ValueMs)
{
T:=DateAdd(Time[1],ValueMs//1000,"Seconds")
ms:=Time[2]+mod(ValueMs,1000)
if (ms>999)
{
ms-=1000
T:=DateAdd(T,1,"Seconds")
}
return [T,format("{:03}",ms)]
}
TimeToMs(Time)
{
HH:=FormatTime(Time,"HH")
MM:=FormatTime(Time,"mm")
SS:=FormatTime(Time,"ss")
return HH*3600000+MM*60000+SS*1000
}
MsToTime(Ms)
{
T:=DateAdd(1601,Ms//1000,"Seconds")
Ms:=format("{:03}",mod(Ms,1000))
return [T,Ms]
}
TTOk(*)
{
ToTime:=this.hTT.Value
tmp1:=DateDiff(A_Now,ToTime,"Seconds")
this.XTOffset:=tmp1*1000-round((this.GPosW/2)/this.PerioT)
this.Pause:=true
this.ShiftStrt:=true
this.GuiGoToT.Hide()
}
TTCancel(*)
{
this.GuiGoToT.Hide()
}
TXOk(*)
{
this.X_Offset:=this.ArrSize[this.Sel]-this.hTX.Value
this.Pause:=true
this.GuiGoToX.Hide()
}
TXCancel(*)
{
this.GuiGoToX.Hide()
}
NameOk(*)
{
this.ArrName[this.Sel]:=this.GuiNameVal.Value
this.GuiName.Hide()
}
NameCancel(*)
{
this.GuiName.Hide()
}
ValAcc(*)
{
if (this.WhichVal="")
return
Whichval:=this.Whichval
if (Whichval="YScale")
{
this.%Whichval%[this.Sel]:=this.GuiValVal.Value
this.AutoScale[this.Sel]:=false
if this.OScale
loop this.AutoScale.Length
this.AutoScale[a_index]:=this.AutoScale[this.Sel]
}
else if (Whichval="ZoomX")
{
this.%Whichval%:=round(this.GuiValVal.Value)
}
else if (Whichval="ZoomT")
{
this.%Whichval%:=round(this.GuiValVal.Value*60000)
}
else if (Whichval="FontSize")
{
this.%Whichval%:=this.GuiValVal.Value
if (this.FontSize!=this.prevSize)
this.SetFont(,this.FontSize)
}
else if (Whichval="Transp")
{
this.%Whichval%[this.Sel]:=round(this.GuiValVal.Value)&0xff
this.Pen[this.Sel]:=this.Transp[this.Sel]<<24|this.Pen[this.Sel]&0xffffff
}
else if (Whichval!="")
{
if (isObject(this.%Whichval%))
this.%Whichval%[this.Sel]:=this.GuiValVal.Value
else
this.%Whichval%:=this.GuiValVal.Value
}
}
ValOk(*)
{
this.ValAcc()
this.WhichVal:=""
this.GuiVal.Hide()
}
ValCancel(*)
{
this.WhichVal:=""
this.GuiVal.Hide()
}
HelpClose(*)
{
this.GuiHelp.Hide()
}
MenuVal(*)
{
this.GuiVal.Show()
}
MenuFlFt(*)
{
this.WhichVal:="FloatFormat"
this.GuiValText1.Value:="Количество знаков после запятой"
this.GuiValVal.Value:=this.FloatFormat
this.GuiValText2.Value:=""
this.MenuVal()
}
MenuName(*)
{
this.GuiNameVal.Value:=this.ArrName[this.Sel]
this.GuiName.Show()
}
MenuGColor(*)
{
tmp1:=ChooseColor(this.Pen[this.Sel],this.GuiGraph.Hwnd)
if (tmp1!="")
{
tmp2:=this.RGBToHSV(tmp1)
if ((tmp2>>8)&0xff=0)
{
tmp3:=(tmp2&0xff)
if (tmp3<127)
tmp3:=127
this.Hue[this.Sel]:=tmp3<<8
}
else
this.Hue[this.Sel]:=tmp2>>16
this.Pen[this.Sel]:=0xff000000 | tmp1
}
}
MenuHelp(*)
{
this.GuiHelp.Show()
}
MenuGoTo(*)
{
if this.ScaleXByTime
{
this.GuiGoToT.Show()
}
else
{
this.GuiGoToX.Show()
}
}
MenuClose(*)
{
this.Hide()
}
MenuPause(*)
{
this.Pause:=!this.Pause
}
MenuForward(*)
{
this.Pause:=false
this.XTOffset:=0
this.X_Offset:=0
this.ShiftStrt:=true
}
MenuBackward(*)
{
this.Pause:=true
this.X_Offset:=this.ArrSize[this.Sel]-this.ZoomX//2
if this.ScaleXByTime
{
if this.TimeStampExist[this.Sel]
tmp1:=DateDiff(A_Now,this.pData[1][2],"Seconds")
else
tmp1:=DateDiff(A_Now,this.StampT[this.Sel][1][1],"Seconds")
this.XTOffset:=tmp1*1000-this.ZoomT//2
}
this.ShiftStrt:=true
}
MenuMarkers(*)
{
Add:=this.Pos.H*8
if this.ShowMarkers:=!this.ShowMarkers
{
Size:=100+Add
this.GuiGraph.Opt("+MinSize300x" Size)
this.GuiGraph.GetPos(,,,&BPosH)
this.GuiGraph.Move(,,,BPosH+Add)
this.MarkerOffset:=Add
}
else
{
this.GuiGraph.Opt("+MinSize300x100")
this.GuiGraph.GetPos(,,,&BPosH)
this.GuiGraph.Move(,,,BPosH-Add)
this.MarkerOffset:=0
}
}
MenuAutoScale(*)
{
if (this.Lock_hi_lim[this.Sel] or this.Lock_lo_lim[this.Sel])
this.AutoScale[this.Sel]:=false
if this.AutoScale[this.Sel]:=!this.AutoScale[this.Sel]
{
this.Lock_hi_lim[this.Sel]:=false
this.Lock_lo_lim[this.Sel]:=false
this.GraphMenuSettings.check(this.mi.MenuAutoScale)
}
else
this.GraphMenuSettings.uncheck(this.mi.MenuAutoScale)
}
MenuAlwaysOnTop(*)
{
if this.AlwaysOnTop:=!this.AlwaysOnTop
{
this.GuiGraph.Opt("+alwaysontop")
this.GraphMenuSettings.check(this.mi.MenuAlwaysOnTop)
}
else
{
this.GuiGraph.Opt("-alwaysontop")
this.GraphMenuSettings.uncheck(this.mi.MenuAlwaysOnTop)
}
}
MenuSmooth(*)
{
if this.Smooth[this.Sel]:=!this.Smooth[this.Sel]
this.GraphMenuSettings.check(this.mi.MenuSmooth)
else
this.GraphMenuSettings.uncheck(this.mi.MenuSmooth)
}
MenuScaleXByTime(*)
{
this.ScaleXByTime:=true
this.GraphMenuSettings.check(this.mi.MenuScaleXByTime)
this.GraphMenuSettings.uncheck(this.mi.MenuScaleXByDots)
}
MenuScaleXByDots(*)
{
this.ScaleXByTime:=false
this.GraphMenuSettings.uncheck(this.mi.MenuScaleXByTime)
this.GraphMenuSettings.check(this.mi.MenuScaleXByDots)
}
MenuResetFont(*)
{
this.FontSize:=12
this.SetFont(,this.FontSize)
}
MenuSave(*)
{
SaveFileName:=FileSelect("S 16",,"Сохранить данные графика","(*.garr)")
if (SaveFileName!="")
{
if !InStr(SaveFileName,".garr")
SaveFileName.=".garr"
o:=this.Data.Clone()
o.Push(this.CreateTime)
o.Push(this.ArrName)
tooltip "Сохраняется..."
ObjDump(SaveFileName,o)
tooltip
msgbox "Сохранено."
}
}
MenuLoad(*)
{
SaveFileName:=FileSelect(3,,"Загрузить данные графика для просмотра","(*.garr)")
if (SaveFileName!="")
this.LoadFile(SaveFileName)
}
DropFiles(GuiObj,GuiCtrlObj,FileArray,X,Y)
{
if instr(FileArray[1],".garr")
this.LoadFile(FileArray[1])
}
LoadFile(File)
{
o:=ObjLoad(File)
this.SaveArrName:=this.ArrName.Clone()
this.ArrName:=[]
for v in o[o.Length]
{
if !isobject(v) and !isNumber(V)
{
this.ArrName:=o.Pop()
this.CreateTime:=o.Pop()
break
}
}
this.NewData:=o
this.MenuBackward()
this.Pause:=true
this.Loaded:=1
}
UpdateMenu()
{
if this.AutoScale[this.Sel]
this.GraphMenuSettings.check(this.mi.MenuAutoScale)
else
this.GraphMenuSettings.uncheck(this.mi.MenuAutoScale)
if this.Smooth[this.Sel]
this.GraphMenuSettings.check(this.mi.MenuSmooth)
else
this.GraphMenuSettings.uncheck(this.mi.MenuSmooth)
}
AHSVToARGB(a:=255,h:=0,s:=0,v:=0)
{
H:=h/255
S:=s/255
V:=v/255
i:=Floor(H*6)
f:=H*6-i
p:=V*(1-S)
q:=V*(1-f*S)
t:=V*(1-(1-f)*S)
sw:=mod(i,6)
if (sw=0)
r:=V, g:=t, b:=p
if (sw=1)
r:=q, g:=V, b:=p
if (sw=2)
r:=p, g:=V, b:=t
if (sw=3)
r:=p, g:=q, b:=V
if (sw=4)
r:=t, g:=p, b:=V
if (sw=5)
r:=V, g:=p, b:=q
r:=(Integer(r*255))&0xff
g:=(Integer(g*255))&0xff
b:=(Integer(b*255))&0xff
return (a<<24 | r<<16 | g<<8 | b)
}
RGBToHSV(RGB)
{
r:=(RGB>>16 & 0xff)/255
g:=(RGB>>8 & 0xff)/255
b:=(RGB & 0xff)/255
min:=(r<g)?((r<b)?r:b):((g<b)?g:b)
val:=(r>g)?((r>b)?r:b):((g>b)?g:b)
delta:=val-min
if (delta=0) ;pure blackness
return (RGB & 0xff)
if (r=val) ;between yellow and magenta
hue:=(g-b)/delta
else if (g=val) ;between cyan and yellow
hue:=2+(b-r)/delta
else ;between magenta and cyan
hue:=4+(r-g)/delta
if (hue<=0)
hue+=6
hue:=round(hue/6*255)
sat:=round((Delta/val)*255)
val:=round(val*255)
return (hue<<16 | sat<<8 | val)
}
Show(x:="",y:="",w:="",h:="")
{
this.GuiHiden:=false
this.GuiGraph.Title:=this.Name
this.GuiGraph.Show((x=""?"":"x" x " ") . (y=""?"":"y" y " ") . (w=""?"":"w" w " ") . (h=""?"":"h" h " "))
if !this.SetParentOnce
{
this.SetParentOnce:=true
DllCall("SetParent","Ptr",this.GuiGDIP.hwnd,"Ptr",this.GuiGraph.hwnd)
WinMove(0,0,,,"ahk_id " this.GuiGDIP.hwnd)
this.GuiGraph.Show()
}
settimer this.UpdateTimer,this.UpdatePeriod
}
Hide(*)
{
this.GuiHiden:=true
settimer this.UpdateTimer,0
this.Update(0)
this.GuiGraph.Hide()
if this.IsChild
this.Parent.DeleteChild(this.IsChild)
}
DeleteChild(Num)
{
loop this.Child.Length
{
if (this.Child[a_index].IsChild=Num)
{
ObjAddRef(ObjPtr(this))
this.Child[a_index]:=""
this.Child.RemoveAt(a_index)
break
}
}
}
Create()
{
this.hDC:=DllCall("CreateCompatibleDC","UPtr",0)
bi:=Buffer(40,0)
NumPut("UInt",40,bi,0)
NumPut("UInt",A_ScreenWidth,bi,4)
NumPut("UInt",A_ScreenHeight,bi,8)
NumPut("UShort",1,bi,12)
NumPut("UShort",32,bi,14)
NumPut("UInt",0,bi,16)
this.hBitmap:=DllCall("CreateDIBSection"
,"Ptr",this.hDC
,"Ptr",bi.Ptr
,"uint",0
,"UPtr*",0
,"Ptr",0
,"uint",0,"Ptr")
this.obm:=DllCall("SelectObject","Ptr",this.hDC,"Ptr",this.hBitmap)
DllCall(Graph.hGdipCreateFromHDC,"Ptr",this.hDC,"UPtr*",&pGraphics:=0)
this.pGraphics:=pGraphics
DllCall(Graph.hGdipSetSmoothingMode,"UPtr",this.pGraphics,"Int",4)
}
Update(Alpha:=255)
{
WinGetClientPos(,,&GPosW,&GPosH,this.GuiGraph.hwnd)
this.GPosW:=GPosW
this.GPosH:=GPosH-this.StampOffset-this.MarkerOffset-this.MenuOffset
this.ZeroPosU:=this.GPosH-this.ZeroPos
if (this.ZeroPosU<0 and this.GPosH_!=GPosH)
{
this.ZeroPos:=GPosH//2
this.ZeroPosU:=this.GPosH-this.ZeroPos
}
this.GPosH_:=GPosH
pt:=Buffer(8,0)
DllCall("UpdateLayeredWindow"
,"Ptr",this.GuiGDIP.Hwnd
,"Ptr",0
,"Ptr",pt.Ptr
,"UInt*",GPosW|GPosH<<32
,"Ptr",this.hDC
,"int64*",0
,"uint",0
,"UInt*",Alpha<<16|1<<24
,"uint",2)
}
CreateSolidBrush(ARGB:=0xff000000)
{
DllCall(Graph.hGdipCreateSolidFill,"UInt",ARGB,"UPtr*",&pBrush:=0)
return pBrush
}
DeleteBrush(pBrush)
{
DllCall(Graph.hGdipDeleteBrush,"UPtr",pBrush)
return 0
}
CreatePen(ARGB:=0xff000000,w:=1)
{
DllCall(Graph.hGdipCreatePen1,"UInt",ARGB,"float",w,"int",2,"UPtr*",&pPen:=0)
return pPen
}
DeletePen(pPen)
{
DllCall(Graph.hGdipDeletePen,"UPtr",pPen)
return 0
}
FillRectangle(ARGB,x,y,w,h)
{
if (!this.pBrush or this.prevBrushColor!=ARGB)
{
if this.pBrush
this.pBrush:=this.DeleteBrush(this.pBrush)
this.pBrush:=this.CreateSolidBrush(ARGB)
}
this.prevBrushColor:=ARGB
DllCall(Graph.hGdipFillRectangle
,"Ptr",this.pGraphics
,"Ptr",this.pBrush
,"float",x
,"float",y
,"float",w
,"float",h)
return {X:x,Y:y,W:w,H:h}
}
DrawLine(ARGB,x1,y1,x2,y2,LineWidth:=1)
{
if (!this.pPen or this.prevPenColor!=ARGB or this.OldLineWidth!=LineWidth)
{
if this.pPen
this.pPen:=this.DeletePen(this.pPen)
this.pPen:=this.CreatePen(ARGB,LineWidth)
}
this.OldLineWidth:=LineWidth
this.prevPenColor:=ARGB
DllCall(Graph.hGdipDrawLine
,"Ptr",this.pGraphics
,"Ptr",this.pPen
,"float",x1
,"float",y1
,"float",x2
,"float",y2)
return {X1:x1,Y1:y1,X2:x2,Y2:y2}
}
DrawLines(ARGB,Points,LineWidth:=1)
{
tmp1:=Points.Length
if !tmp1
return -1
PointF:=Buffer(8*tmp1)
Loop tmp1
{
NumPut("float",Points[a_index][1],PointF,8*(A_Index-1))
NumPut("float",Points[a_index][2],PointF,(8*(A_Index-1))+4)
}
if (!this.pPen or this.prevPenColor!=ARGB or this.OldLineWidth!=LineWidth)
{
if this.pPen
this.pPen:=this.DeletePen(this.pPen)
this.pPen:=this.CreatePen(ARGB,LineWidth)
}
this.OldLineWidth:=LineWidth
this.prevPenColor:=ARGB
return DllCall(Graph.hGdipDrawLines
,"Ptr",this.pGraphics
,"Ptr",this.pPen
,"Ptr",PointF.Ptr
,"int",tmp1)
}
DrawEllipse(ARGB,x,y,w,h,LineWidth:=1)
{
if (!this.pPen or this.prevPenColor!=ARGB or this.OldLineWidth!=LineWidth)
{
if this.pPen
this.pPen:=this.DeletePen(this.pPen)
this.pPen:=this.CreatePen(ARGB,LineWidth)
}
this.OldLineWidth:=LineWidth
this.prevPenColor:=ARGB
DllCall(Graph.hGdipDrawEllipse
,"Ptr",this.pGraphics
,"Ptr",this.pPen
,"float",x
,"float",y
,"float",w
,"float",h)
return {X:x,Y:y,W:w,H:h}
}
DrawRectangle(ARGB,x,y,w,h,LineWidth:=1)
{
if (!this.pPen or this.prevPenColor!=ARGB or this.OldLineWidth!=LineWidth)
{
if this.pPen
this.pPen:=this.DeletePen(this.pPen)
this.pPen:=this.CreatePen(ARGB,LineWidth)
}
this.OldLineWidth:=LineWidth
this.prevPenColor:=ARGB
DllCall(Graph.hGdipDrawRectangle
,"Ptr",this.pGraphics
,"Ptr",this.pPen
,"float",x
,"float",y
,"float",w
,"float",h)
return {X:x,Y:y,W:w,H:h}
}
SetFont(Font:="",Size:="",fStyle:="",NoWrap:="",RenderingHint:="",Vertical:="")
{
Style:=0,Styles:="Regular|Bold|Italic|BoldItalic|Underline|Strikeout"
Loop Parse Styles,"|"
{
if RegExMatch(fStyle, "\b" A_loopField)
Style|=(A_LoopField!="StrikeOut")?(A_Index-1):8
}
if (!this.hFormat
or (this.prevNoWrap!=NoWrap and NoWrap!="")
or (this.prevVertical!=Vertical and Vertical!=""))
{
if this.hFormat
{
DllCall(Graph.hGdipDeleteStringFormat,"UPtr",this.hFormat)
this.hFormat:=""
}
Flags:=0x4000
Flags:=NoWrap?(Flags|0x1000):Flags
Flags:=Vertical?(Flags|0x2):Flags
DllCall(Graph.hGdipCreateStringFormat,"int",Flags,"int",0,"UPtr*",&hFormat:=0)
this.hFormat:=hFormat
this.prevNoWrap:=NoWrap
this.prevVertical:=Vertical
}
if (!this.hFamily or (this.prevFont!=Font and Font!=""))
{
if this.hFamily
{
if this.hFont
{
DllCall(Graph.hGdipDeleteFont,"UPtr",this.hFont)
this.hFont:=""
}
DllCall(Graph.hGdipDeleteFontFamily,"UPtr",this.hFamily)
this.hFamily:=""
}
Font:=Font="" ? "Arial" : Font
; if !A_IsUnicode
; {
; nSize:=DllCall("MultiByteToWideChar","uint",0,"uint",0,"Ptr",&Font,"int",-1,"uint",0,"int",0)
; VarSetCapacity(wFont,nSize*2)
; DllCall("MultiByteToWideChar","uint",0,"uint",0,"Ptr",&Font,"int",-1,"Ptr",&wFont,"int",nSize)
; }
; DllCall(Graph.hGdipCreateFontFamilyFromName
; ,"Ptr",A_IsUnicode ? &Font : &wFont
; ,"uint",0
; ,"UPtr*",hFamily)
DllCall(Graph.hGdipCreateFontFamilyFromName
,"Ptr",StrPtr(String(Font))
,"uint",0
,"UPtr*",&hFamily:=0)
this.hFamily:=hFamily
this.prevFont:=Font
}
if (!this.hFont or (this.prevSize!=Size and Size!="") or (this.prevfStyle!=fStyle and fStyle!=""))
{
if this.hFont
{
DllCall(Graph.hGdipDeleteFont,"UPtr",this.hFont)
this.hFont:=""
}
DllCall(Graph.hGdipCreateFont
,"UPtr",this.hFamily
,"float",(Size ? Size : 12)
,"int",fStyle="" ? 0 : Style
,"int",0
,"UPtr*",&hFont:=0)
this.hFont:=hFont
this.prevSize:=Size
this.prevfStyle:=fStyle
}
RenderingHint:=(RenderingHint="") ? ((this.prevRenderingHint="") ? 0 : this.prevRenderingHint) : RenderingHint
this.prevRenderingHint:=RenderingHint
; SystemDefault = 0
; SingleBitPerPixelGridFit = 1
; SingleBitPerPixel = 2
; AntiAliasGridFit = 3
; AntiAlias = 4
DllCall(Graph.hGdipSetTextRenderingHint,"UPtr",this.pGraphics,"int",RenderingHint)
}
DrawString(Text,xpos:=0,ypos:=0,Width:=0,Height:=0,Options:="Center",Colour:=0xff000000,BackgroundColour:=0)
{
if !(this.hFamily and this.hFont and this.hFormat)
this.SetFont()
Align:=0
Loop Parse "Near|Left|Centre|Center|Far|Right","|"
{
if RegExMatch(Options, "\b" A_loopField)
Align|=Floor(A_Index/2.1) ; 0|0|1|1|2|2
}
DllCall(Graph.hGdipSetStringFormatAlign,"UPtr",this.hFormat,"int",Align)
if (!this.FontpBrush or Colour!=this.prevColour)
{
if this.FontpBrush
this.FontpBrush:=this.DeleteBrush(this.FontpBrush)
this.FontpBrush:=this.CreateSolidBrush(Colour)
this.prevColour:=Colour
}
RC:=this.CreateRectF(xpos,ypos,Width,Height)
ReturnRC:=this.MeasureString(Text,RC)
if (!Width or !Height)
{
Width:=Width ? Width : ReturnRC.W
Height:=Height ? Height : ReturnRC.H
RC:=this.CreateRectF(xpos,ypos,Width,Height)
ReturnRC:=this.MeasureString(Text,RC)
}
if BackgroundColour
this.FillRectangle(BackgroundColour,xpos,ypos,Width,Height)
RegExMatch(Options,"i)Top|Up|Bottom|Down|vCentre|vCenter",&vPos)
if vPos
{
vPos:=SubStr(Options,vPos.Pos,vPos.Len)
if (vPos="vCentre" or vPos="vCenter")
ypos+=(Height-ReturnRC.H)//2
else if (vPos="Top" or vPos="Up")
ypos:=ReturnRC.Y
else if (vPos="Bottom" or vPos="Down")
ypos+=Height-ReturnRC.H
RC:=this.CreateRectF(xpos,ypos,Width,ReturnRC.H)
ReturnRC:=this.MeasureString(Text,RC)
}
; sString:=Text
; if (!A_IsUnicode)
; {
; nSize:=DllCall("MultiByteToWideChar","uint",0,"uint",0,"Ptr",&sString,"int",-1,"Ptr",0,"int",0)
; VarSetCapacity(wString,nSize*2)
; DllCall("MultiByteToWideChar","uint",0,"uint",0,"Ptr",&sString,"int",-1,"Ptr",&wString,"int",nSize)
; }
; DllCall(Graph.hGdipDrawString
; ,"Ptr",this.pGraphics
; ,"Ptr",A_IsUnicode ? &sString : &wString
; ,"int",-1
; ,"Ptr",this.hFont
; ,"Ptr",&RC
; ,"Ptr",this.hFormat
; ,"Ptr",this.FontpBrush)
DllCall(Graph.hGdipDrawString
,"Ptr",this.pGraphics
,"Ptr",StrPtr(String(Text))
,"int",-1
,"Ptr",this.hFont
,"Ptr",RC.Ptr
,"Ptr",this.hFormat
,"Ptr",this.FontpBrush)
return ReturnRC
}
CreateRectF(x,y,w,h)
{
RectF:=Buffer(16)
NumPut("float",x,RectF,0)
NumPut("float",y,RectF,4)
NumPut("float",w,RectF,8)
NumPut("float",h,RectF,12)
return RectF
}
MeasureString(sString,RectF)
{
RC:=Buffer(16)
; if !A_IsUnicode
; {
; nSize:=DllCall("MultiByteToWideChar","uint",0,"uint",0,"Ptr",&sString,"int",-1,"uint",0,"int",0)
; VarSetCapacity(wString,nSize*2)
; DllCall("MultiByteToWideChar","uint",0,"uint",0,"Ptr",&sString,"int",-1,"Ptr",&wString,"int",nSize)
; }
; if !DllCall(Graph.hGdipMeasureString
; ,"Ptr",this.pGraphics
; ,"Ptr",A_IsUnicode ? &sString : &wString
; ,"int",-1
; ,"Ptr",this.hFont
; ,"Ptr",&RectF
; ,"Ptr",this.hFormat
; ,"Ptr",&RC
; ,"uint*",Chars
; ,"uint*",Lines)
if !DllCall(Graph.hGdipMeasureString
,"Ptr",this.pGraphics
,"Ptr",StrPtr(String(sString))
,"int",-1
,"Ptr",this.hFont
,"Ptr",RectF.Ptr
,"Ptr",this.hFormat
,"Ptr",RC.Ptr
,"uint*",&Chars:=0
,"uint*",&Lines:=0)
return {X:Ceil(NumGet(RC,0,"float"))
,Y:Ceil(NumGet(RC,4,"float"))
,W:Ceil(NumGet(RC,8,"float"))
,H:Ceil(NumGet(RC,12,"float"))
,Chars:Chars
,Lines:Lines}
}
}
#HotIf WinActive("ahk_class AutoHotkeyGUI",Graph.WinText)
WheelUp::
{
MouseGetPos(,,&mW)
Graph.WheelUp:=true
Graph.HotKeymW:=mW
}
WheelDown::
{
MouseGetPos(,,&mW)
Graph.WheelDown:=true
Graph.HotKeymW:=mW
}
#HotIf
/* Windows Color Picker Plus
https-//autohotkey.com/board/topic/91229-windows-color-picker-plus/
Edited by me lemasato-
BGR2RGB()-
Use Format() to convert the value to hex instead of SetFormat
Function- ChooseColor([pRGB, hOwner, DlgX, DlgY, Palette])
Displays a standard Windows dialog for choosing colors.
Parameters-
pRGB - The initial color to display in the dialog in RGB format.
The default setting is Black.
hOwner - The Window ID of the dialog's owner, if it has one. Defaults to
0, i.e. no owner. If specified DlgX and DlgY are ignored.
DlgX, DlgY - The X and Y coordinates of the upper left corner of the
dialog. Both default to 0.
Palette - An array of up to 16 RGB color values. These become the
initial custom colors in the dialog.
Remarks-
The custom colors in the dialog are remembered between calls.
If the user selects OK, the Palette array (if it exists) will be loaded
with the custom colors from the dialog.
Returns-
If the user selects OK, the selected color is returned in RGB format
and ErrorLevel is set to 0. Otherwise, the original pRGB value is
returned and ErrorLevel is set to 1.
*/
ChooseColor(pRGB:=0,hOwner:=0,DlgX:=0,DlgY:=0)
{
static CustColors:=Buffer(64,0) ; Custom colors are remembered between calls
static SizeOfCustColors:=CustColors.size
static ChooseColor:=Buffer(9*A_PtrSize,0)
static StructSize:=ChooseColor.size
static Palette:=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
CustData:=(DlgX<<16)|DlgY ; Store X in high word, Y in the low word
;___Load user's custom colors
loop 16
NumPut("UInt",BGR2RGB(Palette[a_index]),CustColors,(A_Index-1)*4)
;___Set up a ChooseColor structure as described in the MSDN
NumPut("UInt",StructSize,ChooseColor,0)
NumPut("UPtr",hOwner,ChooseColor,A_PtrSize)
NumPut("UInt",BGR2RGB(pRGB),ChooseColor,3*A_PtrSize)
NumPut("UPtr",CustColors.Ptr,ChooseColor,4*A_PtrSize)
NumPut("UInt",0x113,ChooseColor,5*A_PtrSize)
NumPut("UInt",CustData,ChooseColor,6*A_PtrSize)
NumPut("UPtr",CallbackCreate(ColorWindowProc),ChooseColor,7*A_PtrSize)
;___Call the function
ErrorLevel:=!DllCall("comdlg32\ChooseColor","UPtr",ChooseColor.Ptr,"UInt")
;___Save the changes made to the custom colors
if !ErrorLevel
Loop 16
Palette[A_Index]:=BGR2RGB(NumGet(CustColors,(A_Index-1)*4,"UInt"))
if !ErrorLevel ; modified by Alectric
return BGR2RGB(NumGet(ChooseColor,3*A_PtrSize,"UINT"))
}
/*!
Function- ColorWindowProc(hwnd, msg, wParam, lParam)
Callback function used to modify the Color dialog before it is displayed
Parameters-
hwnd - Handle to the Color dialog window.
msg - The message sent to the window.
wParam - The handle to the control that has the keyboard focus.
lParam - A pointer to the ChooseColor structure associated with the
Color dialog.
Remarks-
This is intended to be a private function, called only by ChooseColor.
In response to a WM_INITDIALOG message, this function can be used to
modify the Color dialog before it is displayed. Currently it just moves
the window to a new X, Y location.
Returns-
If the hook procedure returns zero, the default dialog box procedure
also processes the message. Otherwise, the default dialog box procedure
ignores the message.
*/
ColorWindowProc(hwnd,msg,wParam,lParam)
{
static WM_INITDIALOG:=0x0110
if (msg!=WM_INITDIALOG)
return 0
hOwner:=NumGet(lParam,A_PtrSize,"UPtr")
if hOwner
return 0
DetectSetting:=A_DetectHiddenWindows
DetectHiddenWindows true
CustData:=NumGet(lParam,6*A_PtrSize,"UInt")
DlgX:=CustData>>16
DlgY:=CustData&0xFFFF
WinMove DlgX,DlgY,,,"ahk_id " hwnd
DetectHiddenWindows DetectSetting
return 0
}
/*!
Function- BGR2RGB(Color)
Converts a BGR color value to a RGB one or vice versa.
Parameters-
Color - The BGR or RGB value to convert
Returns-
The converted value.
*/
BGR2RGB(Color)
{
ret:= (Color & 0xFF000000)
|((Color & 0x00FF0000)>>16)
| (Color & 0x0000FF00)
|((Color & 0x000000FF)<<16)
return ret
}
ObjLoad(addr,&offset:=0) ; load dumped object to variable; from memory (addr is int) or from file (addr is string)
{
; #requires AutoHotkey v2.0.19
If !IsNumber(addr)
{
If !FileExist(addr)
return
sz:=FileGetSize(addr)
If !sz
return
Data:=FileRead(addr,"RAW")
addr:=Data.Ptr
sz:=NumGet(addr,"Int64")
addr+=8
obj:=0
}
; Sizes 1 1 2 2 4 4 8 8 8 x x x x x
; Type.Enum: Char.1 UChar.2 Short.3 UShort.4 Int.5 UInt.6 Int64.7 UInt64.8 Double.9 Str.10 [].11 {}.12 map().13 buffer.14
static types:=["Char","UChar","Short","UShort","Int","UInt","Int64","UInt64","Double"]
static syzes:=[ 2, 2, 3, 3, 5, 5, 9, 9, 9]
typ:=NumGet(addr,offset,"Char")
if (typ<10)
{
obj:=NumGet(addr,offset+1,types[typ])
offset+=syzes[typ]
}
else if (typ=10)
{
size:=NumGet(addr,offset+1,"Int64")
obj:=StrGet(addr+offset+9,size)
offset+=9+size
}
else if (typ=11)
{
obj:=[]
size:=NumGet(addr,offset+1,"Int64")
obj.Length:=size
offset+=9
loop size
obj[a_index]:=ObjLoad(addr,&offset)
}
else if (typ=12)
{
obj:={}
Props:=NumGet(addr,offset+1,"Int64")
offset+=9
loop Props
{
k:=ObjLoad(addr,&offset)
obj.%k%:=ObjLoad(addr,&offset)
}
}
else if (typ=13)
{
obj:=Map()
Props:=NumGet(addr,offset+1,"Int64")
Items:=NumGet(addr,offset+9,"Int64")
offset+=17
loop Props
{
k:=ObjLoad(addr,&offset)
obj.%k%:=ObjLoad(addr,&offset)
}
loop Items
{
i:=ObjLoad(addr,&offset)
obj[i]:=ObjLoad(addr,&offset)
}
}
else if (typ=14)
{
size:=NumGet(addr,offset+1,"Int64")
obj:=Buffer(size)
offset+=9
loop size
NumPut("UChar",NumGet(addr,offset+a_index-1,"UChar"),obj,a_index-1)
offset+=size
}
return obj
}
ObjDump(Path,obj) ; dump object to file
{
critical
; #requires AutoHotkey v2.0.19
if !sz:=RawObjectSize(obj)
return
If FileExist(Path)
FileDelete Path
sz+=8
Data:=Buffer(sz,0)
ptr:=Data.Ptr
NumPut("Int64",sz-8,ptr) ;size of all data
RawObject(obj,ptr+8) ; use this for dumping to memory instead of ObjDump
f:=FileOpen(Path,"rw-rwd","CP0")
Loop (sz//65536)
f.RawWrite(ptr,65536),ptr+=65536
f.RawWrite(ptr,Mod(sz,65536))
f.Close()
return sz
}
RawObject(obj,ptr,offset:=0) ; dump object to memory
{
; #requires AutoHotkey v2.0.19
; Sizes 1 1 2 2 4 4 8 8 8 x x x x x
; Type.Enum: Char.1 UChar.2 Short.3 UShort.4 Int.5 UInt.6 Int64.7 UInt64.8 Double.9 Str.10 [].11 {}.12 map().13 buffer.14
if isObject(Obj)
{
if (Obj.base=[].base)
{
NumPut("Char",11,ptr,offset) ; type
NumPut("Int64",Obj.Length,ptr,offset+1) ; Length of array
offset+=9
loop Obj.Length
offset:=RawObject(Obj[a_index],ptr,offset)
}
else if (Obj.base={}.base)
{
NumPut("Char",12,ptr,offset) ; type
NumPut("Int64",ObjOwnPropCount(Obj),ptr,offset+1) ; num of Props
offset+=9
for k,v in Obj.OwnProps()
{
offset:=RawObject(k,ptr,offset) ; name of prop (str)
offset:=RawObject(v,ptr,offset) ; value of prop (any)
}
}
else if (Obj.base=Map().base)
{
NumPut("Char",13,ptr,offset) ; type
NumPut("Int64",ObjOwnPropCount(Obj),ptr,offset+1) ; num of Props
NumPut("Int64",Obj.Count,ptr,offset+9) ; num of items
offset+=17
for k,v in Obj.OwnProps()
{
offset:=RawObject(k,ptr,offset) ; name of prop (str)
offset:=RawObject(v,ptr,offset) ; value of prop (any)
}
for k,v in Obj
{
offset:=RawObject(k,ptr,offset) ; index of item (any)
offset:=RawObject(v,ptr,offset) ; value of item (any)
}
}
else if (Obj.base=Buffer().base)
{
NumPut("Char",14,ptr,offset) ; type
NumPut("Int64",Obj.size,ptr,offset+1) ; num of bytes
offset+=9
loop Obj.size
NumPut("UChar",NumGet(Obj,a_index-1,"UChar"),ptr,offset+a_index-1) ; Buffer content (RAW)
offset+=Obj.size
}
}
else if IsNumber(obj) ; num
{
NumPut("Char",IsFloat(Obj)?9:Obj>4294967295?8 :Obj>65535?6 :Obj>255?4 :Obj>-1?2 :Obj>-129?1 :Obj>-32769?3 :Obj>-2147483649?5 :7,ptr,offset+0)
NumPut(IsFloat(Obj)?"Double":Obj>4294967295?"UInt64":Obj>65535?"UInt":Obj>255?"UShort":Obj>-1?"UChar":Obj>-129?"Char":Obj>-32769?"Short":Obj>-2147483649?"Int":"Int64",Obj,ptr,offset+1)
offset+= IsFloat(Obj)||Obj>4294967295?9 :Obj>65535?5 :Obj>255?3 :Obj>-129?2 :Obj>-32769?3 :Obj>-2147483649?5 :9
}
else ; string
{
NumPut("Char",10,ptr,offset) ; type
NumPut("Int64",sz:=StrPut(Obj,ptr+offset+9),ptr,offset+1) ; (str size) string text
offset+=sz+9
}
return offset
}
RawObjectSize(Obj,sz:=0) ; get object's size in dumped condition
{
; #requires AutoHotkey v2.0.19
if isObject(Obj)
{
if (Obj.base=[].base)
{
sz+=9 ; 1 (type) + 8 (num of items)
loop Obj.Length
sz:=RawObjectSize(Obj[a_index],sz)
}
else if (Obj.base={}.base)
{
sz+=9 ; 1 (type) + 8 (num of prop)
for k,v in Obj.OwnProps()
{
sz:=RawObjectSize(k,sz) ; name of prop (str)
sz:=RawObjectSize(v,sz) ; value of prop (any)
}
}
else if (Obj.base=Map().base)
{
sz+=17 ; 1 (type) + 8 (size of Props) + 8 (size of array)
for k,v in Obj.OwnProps()
{
sz:=RawObjectSize(k,sz) ; name of prop (str)
sz:=RawObjectSize(v,sz) ; value of prop (any)
}
for k,v in Obj
{
sz:=RawObjectSize(k,sz) ; index
sz:=RawObjectSize(v,sz) ; value
}
}
else if (Obj.base=Buffer().base) ; sz = 1 (type) + 8 (size) + (buffer size)
sz+=9+Obj.size
else
{
MsgBox "Unsupported object type: `"" Type(obj) "`".","ObjDump",0x30
return 0
}
}
else if IsNumber(obj) ; sz = 1 (type) + (size of data type)
sz+=IsFloat(Obj)||Obj>4294967295?9:Obj>65535?5:Obj>255?3:Obj>-129?2:Obj>-32769?3:Obj>-2147483649?5:9
else ; sz = 1 (type) + 8 (size) + (str size)
sz+=9+StrPut(Obj)
return sz
}