Orion9

|
Posted: Mon Sep 07, 2026 14:09 Post subject: |
|
|
Кнопка для отображения погоды по заданным координатам.
 Hidden text TOTALCMD#BAR#DATA
%COMMANDER_PATH%\Scripts\Ahk\AutoHotkey32.exe
Meteo.ahk -tooltip-gps 55.75 37.62 Москва
%COMMANDER_PATH%\Scripts\Ahk\AutoHotkey32.exe,2
Москва
%COMMANDER_PATH%\Ini\Title\
-1
Для работы требуется Autohotkey второй версии:
https://www.autohotkey.com/download/
Путь к исполняемому файлу и каталогу скрипта можно заменить на свои.
Скрипт делает запрос к сайту open-meteo.com (открытый и бесплатный API для получения данных о погоде):
https://open-meteo.com/en/docs
Чтобы определить местоположение и координаты, можно воспользоваться:
https://open-meteo.com/en/docs/geocoding-api
Скрипт принимает четыре параметра: -gps, latitude, longitude, name (широта, долгота и имя). Имя может быть любым, т.к. оно используется только для обозначения местоположения.
Пятый параметр -forcast необязательный. Он используется для отображения прогноза на 24 часа и на 48 часов соответственно, и может быть только двух значений: либо -forcast24, либо -forcast48. Если этот параметр не задан, подсказка будет выглядеть стандартно, т.е. с прогнозом на 8 часов и 7 дней недели. В скрипте этими значениями можно управлять через HourVar и WeekVar.
Параметр -gps может присоединить к себе либо -tooltip, -msgbox. Если ни один из них не указан, вывод будет осуществлен в стандартное устройство вывода (например, для использования в других скриптах). Стиль подсказки в пределах допустимого можно изменить в ToolTipOptions.
Пример параметров:
| Code: | Meteo.ahk -msgbox-gps 40.71 -74.00 "New York" |
Будет показан MsgBox с информацией о погоде в Нью-Йорке по местному времени.
| Code: | Meteo.ahk -msgbox-gps 40.71 -74.00 "New York" -forecast24 |
То же самое, только прогноз на 24 часа.
| Code: | Meteo.ahk -tooltip-gps 55.75 37.62 Москва |
Будет отображен тултип (подсказка) о погоде в Москве:
 Hidden text
| Code: | Meteo.ahk -tooltip-gps 55.75 37.62 Москва -forecast24 |
То же самое, но с прогнозом на 24 часа:
 Hidden text
Кроме параметров, возможно использование клавиш-модификаторов, где CTRL - прогноз на 24 часа, CTRL+Shift - прогноз на 48 часов, Win - MsgBox, Alt - использовать локальный файл (т.е. не загружать из интернета)
Локальный файл сохраняется во временном каталоге с именем forecast.json
Для корректной работы скрипт нужно сохранить в кодировке UTF-8:
 Meteo.ahk | Code: | #Requires AutoHotkey v2
#NoTrayIcon
Global IsAlt := GetKeyState("Alt", "P"), IsShift := GetKeyState("Shift", "P")
Global IsWin := GetKeyState("LWin", "P"), IsControl := GetKeyState("Control", "P")
Global MeteoFormat := "{Temperature} Wind: {Wind} {Direction}"
Global STDOUT := "", WEATHER := ""
Global Forecast := 0, HourVar := 8, WeekVar := 1
Global Latitude, Longitude, MeteoName, IsMeteoName := 0
Global ActiveToolTip := false, LocalFile := IsAlt
Global meteo_url := "", meteo_api := "¤t=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,cloud_cover,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,relative_humidity_2m,surface_pressure,weather_code,wind_speed_10m,wind_direction_10m&daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_sum&wind_speed_unit=ms&timezone=auto"
if A_Args.Length < 1
{
MsgBox "Недостаточно аргументов"
ExitApp
}
if !InStr(A_Args[1],'-gps')
{
MsgBox "Не найден аргумент -gps"
ExitApp
}
if A_Args.Length > 3
{
Latitude := A_Args[2]
Longitude := A_Args[3]
MeteoName := A_Args[4]
}
else
{
MsgBox "Недостаточно аргументов"
ExitApp
}
;MeteoName := MeteoName <> "" ? MeteoName : "Unknown"
Latitude := IsNumber(Latitude) ? Latitude : 0
Longitude := IsNumber(Longitude) ? Longitude : 0
if Latitude = 0 or Longitude = 0
{
MsgBox "Неверное значение Latitude или Longitude"
ExitApp
}
meteo_url := "https://api.open-meteo.com/v1/forecast?latitude=" Latitude "&longitude=" Longitude . meteo_api
if A_Args.Length > 4 and InStr(A_Args[5],'-forecast')
{
Forecast := InStr(A_Args[5],'48') ? 48 : 24
}
if IsControl
{
if IsShift
Forecast := 48
else
Forecast := 24
}
fMeteo()
STDOUT := MeteoName ": " WEATHER "`n" STDOUT
If IsAlt
STDOUT := "(L) " . STDOUT
if IsWin
{
MsgBox STDOUT
ExitApp
}
if InStr(A_Args[1],'-tooltip')
{
ToolTipOptions.Init()
ToolTipOptions.SetFont("s8", "Tahoma")
ToolTipOptions.SetMargins(1, 1, 1, 1)
;ToolTipOptions.SetTitle("Meteo" , 1)
ToolTipOptions.SetColors("FFFFE1", "BLACK")
ToolTip STDOUT
ActiveToolTip := true
KeyWait "LButton", "D"
ExitApp
}
if InStr(A_Args[1],'-msgbox')
{
MsgBox STDOUT
ExitApp
}
try FileAppend RTrim(LTrim(STDOUT), "`n"), "*", "CP0"
ExitApp
ESC::
{
if ActiveToolTip
{
ExitApp
}
}
fMeteo()
{
json_file := meteo_url
json_temp := A_Temp . "\forecast.json"
Global bMeteo := 1
try
{
if !LocalFile
Download json_file, json_temp
}
catch
{
Global STDOUT .= "Meteo #Download Error`n"
}
else
{
ParseMeteo()
}
ParseMeteo()
{
try
file := FileRead(json_temp, "UTF-8")
catch
{
Global STDOUT .= "Meteo #Error Reading File:`n" . json_temp . "`n"
Return
}
try
json := Jxon_load(&file)
catch
{
Global STDOUT .= "Meteo #Json File Corrupt:`n" . json_temp . "`n"
Return
}
out := ''
try
{
cord := Round(json["latitude"],2) '° N ' Round(json["longitude"],2) '° E'
time := json["current"]["time"]
temp := ValueSign(Round(json["current"]["temperature_2m"])) . json["current_units"]["temperature_2m"]
feel := ValueSign(Round(json["current"]["apparent_temperature"])) . json["current_units"]["apparent_temperature"]
humd := Round(json["current"]["relative_humidity_2m"]) . json["current_units"]["relative_humidity_2m"]
prec := Format("{:.2f}", json["current"]["precipitation"]) . ' ' . json["current_units"]["precipitation"]
code := json["current"]["weather_code"]
clod := json["current"]["cloud_cover"] . json["current_units"]["cloud_cover"]
pres := Round(json["current"]["surface_pressure"] * 0.75) . ' mm'
wind := Round(json["current"]["wind_speed_10m"]) . ' ' . json["current_units"]["wind_speed_10m"]
from := Round(json["current"]["wind_direction_10m"]) . json["current_units"]["wind_direction_10m"]
gust := Round(json["current"]["wind_gusts_10m"]) . ' ' . json["current_units"]["wind_gusts_10m"]
;if Forecast = 0
out .= '---------------------------------------------------------------------------`n'
out .= 'GPS ' . cord . (IsMeteoName = 1 ? ' ' MeteoName '': "") . '`n'
out .= 'Высота ' Round(json["elevation"]) ' м.`n'
out .= 'Погода на ' . StrReplace(time, "T", " / ") . '`n'
out .= '---------------------------------------------------------------------------`n'
out .= 'Температура ' . temp . '`n'
out .= 'Ощущается как ' . feel . '`n'
if Forecast = 0
{
out .= 'Влажность ' . humd . '`n'
out .= GetWeatherCode(code) . ', Облака ' . clod . '`n'
out .= json["current"]["precipitation"] > 0 ? 'Осадки ' . prec . '`n' : 'Без осадков`n'
out .= 'Давление ' . pres . '`n'
out .= 'Ветер ' . wind . '`n'
out .= 'Направление ' . from . ', ' . WindDirection(Round(json["current"]["wind_direction_10m"])) . '`n'
out .= 'Порывы ветра ' . gust . '`n'
}
try
{
t := SubStr(time, InStr(time, "T"), 4)
d := f7 := ''
if Forecast = 0
day .= 'Прогноз на ' . HourVar . ' часов:`n'
else
day .= 'Прогноз на ' (Forecast = 48 ? '48 часов' : '24 часа') ':`n'
day .= '---------------------------------------------------------------------------`n'
day .= 'Дата Время Темп Ветер Нап Дав Влаж Погода`n'
day .= '---------------------------------------------------------------------------`n'
j := 0
f := 0
h := (Forecast = 48) ? 3 : 2
for i in json["hourly"]["time"]
{
if j > 0 and j < h
{
d := SubStr(StrReplace(json["hourly"]["time"][A_Index], "T", " "), 6) .
' ' Round(json["hourly"]["temperature_2m"][A_Index]) json["hourly_units"]["temperature_2m"] .
' ' Round(json["hourly"]["wind_speed_10m"][A_Index]) ' ' json["hourly_units"]["wind_speed_10m"] .
' ' Round(json["hourly"]["wind_direction_10m"][A_Index]) json["hourly_units"]["wind_direction_10m"] .
' ' Round(json["hourly"]["surface_pressure"][A_Index] * 0.75) .
' ' Round(json["hourly"]["relative_humidity_2m"][A_Index]) json["hourly_units"]["relative_humidity_2m"] .
' ' GetWeatherCode(json["hourly"]["weather_code"][A_Index]) . '`n'
if StrLen(d) > 59
{
d := SubStr(d, 1, 58) . "`n"
}
day .= d
if ++f = HourVar and Forecast = 0
f7 := day
}
if InStr(i, t) and ++j=2
{
out .= 'Завтра в это время ' .
ValueSign(Round(json["hourly"]["temperature_2m"][A_Index])) .
json["hourly_units"]["temperature_2m"] ', ' .
GetWeatherCode(json["hourly"]["weather_code"][A_Index]) . '`n'
}
}
day := out . day
out .= (Forecast = 0) ? f7 : day
}
catch
out .= '# Error getting hourly data...`n'
o := ''
if WeekVar > 0
{
try
{
out .= 'Прогноз на неделю:`n'
out .= '---------------------------------------------------------------------------`n'
out .= 'Осд Всхд Закат Макс Мин Дата Погода`n'
out .= '---------------------------------------------------------------------------`n'
Loop json["daily"]["time"].Length
{
i := A_Index
for k, v in json["daily"]
{
if InStr(k,'temp') {
if Round(v[i]) < 10 and Round(v[i]) > -10
o .= ""
o .= Round(v[i]) ;json["daily_units"][k]
}
else if InStr(k,'code')
o .= GetWeatherCode(v[i])
else if InStr(k,'sun')
o .= StrSplit(v[i],'T')[2]
else if InStr(k,'prec')
o .= Round(v[i],1)
else
o .= v[i]
o .= ' '
}
o .= '`n'
}
c := ''
Loop Parse, o, '`n'
{
if StrLen(A_LoopField) > 58 {
c .= SubStr(A_LoopField, 1, 57) . "`n"
}
else if StrLen(A_LoopField) > 0 {
c .= A_LoopField . '`n'
}
}
out.=c
}
catch
out.='# Error parcing daily data...`n'
}
}
catch
{
;Throw
Global STDOUT .= "Meteo #Error Parcing Json File:`n" . json_temp . "`nRequired Values Not Found`n"
Return
}
else
{
Global STDOUT .= (Forecast > 0) ? day : out
Global MeteoFormat := StrReplace(MeteoFormat, "{Temperature}", temp)
Global MeteoFormat := StrReplace(MeteoFormat, "{Wind}", wind)
Global MeteoFormat := StrReplace(MeteoFormat, "{Direction}", from)
;Global WEATHER := 'Meteo: ' . temp . ' Wind: ' . wind . ' ' . from
Global WEATHER := MeteoFormat
}
}
ValueSign(Val)
{
if Val > -1
Val := '+' . Val
return Val
}
GetWeatherCode(Code)
{
sWeather:=""
Switch Code
{
case 0:
sWeather:= "Ясно" ;"Clear"
case 1:
sWeather:= "Малооблачно" ;"Mainly clear"
case 2:
sWeather:= Random(1) = 1 ? "Облачно с прояснениями" : "Переменная облачность" ;"Partly cloudy"
case 3:
sWeather:= "Пасмурно" ;"Overcast"
case 45:
sWeather:= "Туман" ;"Fog"
case 48:
sWeather:= "Изморозь" ;"Depositing rime fog"
case 51:
sWeather:= "Слабый моросящий дождь" ;"Light drizzle"
case 53:
sWeather:= "Моросящий дождь" ;"Moderate drizzle"
case 55:
sWeather:= "Сильный моросящий дождь" ;"Dense intensity drizzle"
case 56:
sWeather:= "Замерзающая морось" ;"Freezing Drizzle: Light"
case 57:
sWeather:= "Замерзающая морось" ;"Freezing Drizzle: dense intensity"
case 61:
sWeather:= "Слабый дождь" ;"Rain: Slight"
case 63:
sWeather:= "Дождь" ;"Rain: moderate"
case 65:
sWeather:= "Сильный дождь" ;"Rain: heavy intensity"
case 66:
sWeather:= "Слабый ледяной дождь" ;"Freezing Rain: Light"
case 67:
sWeather:= "Ледяной дождь" ;"Freezing Rain: heavy intensity"
case 71:
sWeather:= "Слабый снег" ;"Snow fall: Slight"
case 73:
sWeather:= "Снег" ;"Snow fall: moderate"
case 75:
sWeather:= "Сильный снег" ;"Snow fall: heavy intensity"
case 77:
sWeather:= "Зернистый снег" ;"Snow grains"
case 80:
sWeather:= "Проливной дождь" ;"Rain showers: Slight"
case 81:
sWeather:= "Ливень" ;"Rain showers: moderate"
case 82:
sWeather:= "Сильный ливень" ;"Rain showers: violent"
case 85:
sWeather:= "Мокрый снег" ;"Snow showers slight"
case 86:
sWeather:= "Дождь со снегом" ;"Snow showers heavy"
case 95:
sWeather:= "Гроза" ;"Thunderstorm: Slight or moderate"
case 96:
sWeather:= "Гроза, град" ;"Thunderstorm with slight and heavy hail"
case 99:
sWeather:= "Гроза, град" ;"Thunderstorm with slight and heavy hail"
Default:
sWeather:= "Не найден код " . Code
}
Return sWeather
}
WindDirection(wd)
{
Switch
{
case wd < 12: Wind := "Северный"
case wd < 33: Wind := "Северо-Северо-Восточный"
case wd < 57: Wind := "Северо-Восточный"
case wd < 78: Wind := "Восточно-Северо-Восточный"
case wd < 101: Wind := "Восточный"
case wd < 123: Wind := "Восточно-Юго-Восточный"
case wd < 147: Wind := "Юго-Восточный"
case wd < 169: Wind := "Юго-Юго-Восточный"
case wd < 192: Wind := "Южный"
case wd < 215: Wind := "Юго-Юго-Западный"
case wd < 238: Wind := "Юго-Западный"
case wd < 260: Wind := "Западно-Юго-Западный"
case wd < 283: Wind := "Западный"
case wd < 305: Wind := "Западно-Северо-Западный"
case wd < 328: Wind := "Северо-Западный"
case wd < 350: Wind := "Северо-Северо-Западный"
case wd < 361: Wind := "Северный"
Default: Wind := "Не известно"
}
Return Wind
}
}
;https://github.com/cocobelgica/AutoHotkey-JSON/blob/master/Jxon.ahk
Jxon_Load(&src, args*) {
key := "", is_key := false
stack := [ tree := [] ]
next := '"{[01234567890-tfn'
pos := 0
while ( (ch := SubStr(src, ++pos, 1)) != "" ) {
if InStr(" `t`n`r", ch)
continue
if !InStr(next, ch, true) {
testArr := StrSplit(SubStr(src, 1, pos), "`n")
ln := testArr.Length
col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))
msg := Format("{}: line {} col {} (char {})"
, (next == "") ? ["Extra data", ch := SubStr(src, pos)][1]
: (next == "'") ? "Unterminated string starting at"
: (next == "\") ? "Invalid \escape"
: (next == ":") ? "Expecting ':' delimiter"
: (next == '"') ? "Expecting object key enclosed in double quotes"
: (next == '"}') ? "Expecting object key enclosed in double quotes or object closing '}'"
: (next == ",}") ? "Expecting ',' delimiter or object closing '}'"
: (next == ",]") ? "Expecting ',' delimiter or array closing ']'"
: [ "Expecting JSON value(string, number, [true, false, null], object or array)"
, ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
, ln, col, pos)
throw Error(msg, -1, ch)
}
obj := stack[1]
is_array := (obj is Array)
if i := InStr("{[", ch) { ; start new object / map?
val := (i = 1) ? Map() : Array() ; ahk v2
is_array ? obj.Push(val) : obj[key] := val
stack.InsertAt(1,val)
next := '"' ((is_key := (ch == "{")) ? "}" : "{[]0123456789-tfn")
} else if InStr("}]", ch) {
stack.RemoveAt(1)
next := (stack[1]==tree) ? "" : (stack[1] is Array) ? ",]" : ",}"
} else if InStr(",:", ch) {
is_key := (!is_array && ch == ",")
next := is_key ? '"' : '"{[0123456789-tfn'
} else { ; string | number | true | false | null
if (ch == '"') { ; string
i := pos
while i := InStr(src, '"',, i+1) {
val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
if (SubStr(val, -1) != "\")
break
}
if !i ? (pos--, next := "'") : 0
continue
pos := i ; update pos
val := StrReplace(val, "\/", "/")
val := StrReplace(val, '\"', '"')
, val := StrReplace(val, "\b", "`b")
, val := StrReplace(val, "\f", "`f")
, val := StrReplace(val, "\n", "`n")
, val := StrReplace(val, "\r", "`r")
, val := StrReplace(val, "\t", "`t")
i := 0
while i := InStr(val, "\",, i+1) {
if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
continue 2
xxxx := Abs("0x" . SubStr(val, i+2, 4)) ; \uXXXX - JSON unicode escape sequence
if (xxxx < 0x100)
val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
}
if is_key {
key := val, next := ":"
continue
}
} else { ; number | true | false | null
val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
if IsInteger(val)
val += 0
else if IsFloat(val)
val += 0
else if (val == "true" || val == "false")
val := (val == "true")
else if (val == "null")
val := ""
else if is_key {
pos--, next := "#"
continue
}
pos += i-1
}
is_array ? obj.Push(val) : obj[key] := val
next := obj == tree ? "" : is_array ? ",]" : ",}"
}
}
return tree[1]
}
;https://www.autohotkey.com/boards/viewtopic.php?t=113308
;======================================================================================================================
; ToolTipOptions - additional options for ToolTips
;
; Tooltip control -> https://learn.microsoft.com/en-us/windows/win32/controls/tooltip-control-reference
; TTM_SETMARGIN = 1050
; TTM_SETTIPBKCOLOR = 1043
; TTM_SETTIPTEXTCOLOR = 1044
; TTM_SETTITLEW = 1057
; WM_SETFONT = 0x30
; SetClassLong() -> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongw
; ======================================================================================================================
Class ToolTipOptions {
; -------------------------------------------------------------------------------------------------------------------
Static HTT := DllCall("User32.dll\CreateWindowEx", "UInt", 8, "Str", "tooltips_class32", "Ptr", 0, "UInt", 3
, "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr", A_ScriptHwnd, "Ptr", 0, "Ptr", 0, "Ptr", 0)
Static SWP := CallbackCreate(ObjBindMethod(ToolTipOptions, "_WNDPROC_"), , 4) ; subclass window proc
Static OWP := 0 ; original window proc
Static ToolTips := Map()
; -------------------------------------------------------------------------------------------------------------------
Static BkgColor := ""
Static TktColor := ""
Static Icon := ""
Static Title := ""
Static HFONT := 0
Static Margins := ""
; -------------------------------------------------------------------------------------------------------------------
Static Call(*) => False ; do not create instances
; -------------------------------------------------------------------------------------------------------------------
; Init() - Initialize some class variables and subclass the tooltip control.
; -------------------------------------------------------------------------------------------------------------------
Static Init() {
If (This.OWP = 0) {
This.BkgColor := ""
This.TktColor := ""
This.Icon := ""
This.Title := ""
This.Margins := ""
If (A_PtrSize = 8)
This.OWP := DllCall("User32.dll\SetClassLongPtr", "Ptr", This.HTT, "Int", -24, "Ptr", This.SWP, "UPtr")
Else
This.OWP := DllCall("User32.dll\SetClassLongW", "Ptr", This.HTT, "Int", -24, "Int", This.SWP, "UInt")
OnExit(ToolTipOptions._EXIT_, -1)
Return This.OWP
}
Else
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Reset() - Close all existing tooltips, delete the font object, and remove the tooltip's subclass.
; -------------------------------------------------------------------------------------------------------------------
Static Reset() {
If (This.OWP != 0) {
For HWND In This.ToolTips.Clone()
DllCall("DestroyWindow", "Ptr", HWND)
This.ToolTips.Clear()
If This.HFONT
DllCall("DeleteObject", "Ptr", This.HFONT)
This.HFONT := 0
If (A_PtrSize = 8)
DllCall("User32.dll\SetClassLongPtrW", "Ptr", This.HTT, "Int", -24, "Ptr", This.OWP, "UPtr")
Else
DllCall("User32.dll\SetClassLongW", "Ptr", This.HTT, "Int", -24, "Int", This.OWP, "UInt")
This.OWP := 0
Return True
}
Else
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; SetColors() - Set or remove the text and/or the background color for the tooltip.
; Parameters:
; BkgColor - color value like used in Gui.BackColor(...)
; TxtColor - see above.
; -------------------------------------------------------------------------------------------------------------------
Static SetColors(BkgColor := "", TxtColor := "") {
This.BkgColor := BkgColor = "" ? "" : BGR(BkgColor)
This.TxtColor := TxtColor = "" ? "" : BGR(TxtColor)
BGR(Color, Default := "") { ; converts colors to BGR
; HTML Colors (BGR)
Static HTML := {AQUA: 0xFFFF00, BLACK: 0x000000, BLUE: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080,
GREEN: 0x008000, LIME: 0x00FF00, MAROON: 0x000080, NAVY: 0x800000, OLIVE: 0x008080,
PURPLE: 0x800080, RED: 0x0000FF, SILVER: 0xC0C0C0, TEAL: 0x808000, WHITE: 0xFFFFFF,
YELLOW: 0x00FFFF}
If HTML.HasProp(Color)
Return HTML.%Color%
If (Color Is String) && IsXDigit(Color) && (StrLen(Color) = 6)
Color := Integer("0x" . Color)
If IsInteger(Color)
Return ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16)
Return Default
}
}
; -------------------------------------------------------------------------------------------------------------------
; SetFont() - Set or remove the font used by the tooltip.
; Parameters:
; FntOpts - font options like Gui.SetFont(Options, ...)
; FntName - font name like Gui.SetFont(..., Name)
; -------------------------------------------------------------------------------------------------------------------
Static SetFont(FntOpts := "", FntName := "") {
Static HDEF := DllCall("GetStockObject", "Int", 17, "UPtr") ; DEFAULT_GUI_FONT
Static LOGFONTW := 0
If (FntOpts = "") && (FntName = "") {
If This.HFONT
DllCall("DeleteObject", "Ptr", This.HFONT)
This.HFONT := 0
LOGFONTW := 0
}
Else {
If (LOGFONTW = 0) {
LOGFONTW := Buffer(92, 0)
DllCall("GetObject", "Ptr", HDEF, "Int", 92, "Ptr", LOGFONTW)
}
HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
LOGPIXELSY := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 90, "Int")
DllCall("ReleaseDC", "Ptr", HDC, "Ptr", 0)
If (FntOpts != "") {
For Opt In StrSplit(RegExReplace(Trim(FntOpts), "\s+", " "), " ") {
Switch StrUpper(Opt) {
Case "BOLD": NumPut("Int", 700, LOGFONTW, 16)
Case "ITALIC": NumPut("Char", 1, LOGFONTW, 20)
Case "UNDERLINE": NumPut("Char", 1, LOGFONTW, 21)
Case "STRIKE": NumPut("Char", 1, LOGFONTW, 22)
Case "NORM": NumPut("Int", 400, "Char", 0, "Char", 0, "Char", 0, LOGFONTW, 16)
Default:
O := StrUpper(SubStr(Opt, 1, 1))
V := SubStr(Opt, 2)
Switch O {
Case "C":
Continue ; ignore the color option
Case "Q":
If !IsInteger(V) || (Integer(V) < 0) || (Integer(V) > 5)
Throw ValueError("Option Q must be an integer between 0 and 5!", -1, V)
NumPut("Char", Integer(V), LOGFONTW, 26)
Case "S":
If !IsNumber(V) || (Number(V) < 1) || (Integer(V) > 255)
Throw ValueError("Option S must be a number between 1 and 255!", -1, V)
NumPut("Int", -Round(Integer(V + 0.5) * LOGPIXELSY / 72), LOGFONTW)
Case "W":
If !IsInteger(V) || (Integer(V) < 1) || (Integer(V) > 1000)
Throw ValueError("Option W must be an integer between 1 and 1000!", -1, V)
NumPut("Int", Integer(V), LOGFONTW, 16)
Default:
Throw ValueError("Invalid font option!", -1, Opt)
}
}
}
}
NumPut("Char", 1, "Char", 4, "Char", 0, LOGFONTW, 23) ; DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS
NumPut("Char", 0, LOGFONTW, 27) ; FF_DONTCARE
If (FntName != "")
StrPut(FntName, LOGFONTW.Ptr + 28, 32)
If !(HFONT := DllCall("CreateFontIndirectW", "Ptr", LOGFONTW, "UPtr"))
Throw OSError()
If This.HFONT
DllCall("DeleteObject", "Ptr", This.HFONT)
This.HFONT := HFONT
}
}
; -------------------------------------------------------------------------------------------------------------------
; SetMargins() - Set or remove the margins used by the tooltip
; Parameters:
; L, T, R, B - left, top, right, and bottom margin in pixels.
; -------------------------------------------------------------------------------------------------------------------
Static SetMargins(L := 0, T := 0, R := 0, B := 0) {
If ((L + T + R + B) = 0)
This.Margins := 0
Else {
This.Margins := Buffer(16, 0)
NumPut("Int", L, "Int", T, "Int", R, "Int", B, This.Margins)
}
}
; -------------------------------------------------------------------------------------------------------------------
; SetTitle() - Set or remove the title and/or the icon displayed on the tooltip.
; Parameters:
; Title - string to be used as title.
; Icon - icon to be shown in the ToolTip.
; This can be the number of a predefined icon (1 = info, 2 = warning, 3 = error
; (add 3 to display large icons on Vista+) or a HICON handle.
; -------------------------------------------------------------------------------------------------------------------
Static SetTitle(Title := "", Icon := "") {
Switch {
Case (Title = "") && (Icon != ""):
This.Icon := Icon
This.Title := " "
Case (Title != "") && (Icon = ""):
This.Icon := 0
This.Title := Title
Default:
This.Icon := Icon
This.Title := Title
}
}
; -------------------------------------------------------------------------------------------------------------------
; For internal use only!
; -------------------------------------------------------------------------------------------------------------------
Static _WNDPROC_(hWnd, uMsg, wParam, lParam) {
; WNDPROC -> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
Switch uMsg {
Case 0x0411: ; TTM_TRACKACTIVATE - just handle the first message after the control has been created
If This.ToolTips.Has(hWnd) && (This.ToolTips[hWnd] = 0) {
If (This.BkgColor != "")
SendMessage(1043, This.BkgColor, 0, hWnd) ; TTM_SETTIPBKCOLOR
If (This.TxtColor != "")
SendMessage(1044, This.TxtColor, 0, hWnd) ; TTM_SETTIPTEXTCOLOR
If This.HFONT
SendMessage(0x30, This.HFONT, 0, hWnd) ; WM_SETFONT
If (Type(This.Margins) = "Buffer")
SendMessage(1050, 0, This.Margins.Ptr, hWnd) ; TTM_SETMARGIN
If (This.Icon != "") || (This.Title != "")
SendMessage(1057, This.Icon, StrPtr(This.Title), hWnd) ; TTM_SETTITLE
This.ToolTips[hWnd] := 1
}
Case 0x0001: ; WM_CREATE
DllCall("UxTheme.dll\SetWindowTheme", "Ptr", hWnd, "Ptr", 0, "Ptr", StrPtr(""))
This.ToolTips[hWnd] := 0
Case 0x0002: ; WM_DESTROY
This.ToolTips.Delete(hWnd)
}
Return DllCall(This.OWP, "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam, "UInt")
}
; -------------------------------------------------------------------------------------------------------------------
Static _EXIT_(*) {
If (ToolTipOptions.OWP != 0)
ToolTipOptions.Reset()
}
} |
|
|