Orion9

|
Posted: Thu Dec 04, 2025 00:39 Post subject: |
|
|
Добавил к функции tip() флаг TTF_PARSELINKS, позволяющий вставлять в текст подсказки гиперссылки. Функцию пришлось немного доработать, чтобы она могла самостоятельно перехватывать клики по ссылкам. Последняя версия:
 Hidden text | Code: | Global gTipText, gTipX, gTipY, gTipMenuItems
Global gTipWndProc, gTipWP = Callback("tipwp", "hwnd;uint;wparam;lparam")
#{
nFlags:
1 - Previous window position
2 - Square tooltip window
4 - Inactive tooltip window
0 - Default
#}
Func tip(sText, nIcon = 0, sTitle = "Tip", nFlags = 0, sMenuItems = "")
Static TTM_TRACKACTIVATE = 1041, _
TTM_TRACKPOSITION = 1042, _
TTM_SETMAXTIPWIDTH = 1048, _
TTM_SETTITLE = 1057, _
TTM_ADDTOOL = 1074, _
TTM_UPDATETIPTEXT = 1081
Static txt = Buffer(1024*2)
Static hTip = 0, buf = Buffer(auX64 ? 56 : 40)
Local nMaxWidth = 200
If hTip = 0 Then
# TTS_BALLOON | TTS_CLOSE | TTS_NOPREFIX
hTip = DllCall("CreateWindowExW", _
"dword", 8, _
"wstr", "tooltips_class32", _
"wstr", "", "dword", 0x00000c2, _
"int", 0, "int", 0, "int", 0, "int", 0, _
"handle", 0, _
"handle", 0, "handle", 0, "ptr", 0, "handle")
If hTip = 0 Then
MsgBox("Не удалось создать окно подсказки")
Return 0
EndIf
gTipWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
"hwnd", hTip, "int", -4, "long_ptr", gTipWP.Ptr, "ptr")
txt.Zero()
txt.SetStr(sTitle & Chr(0))
SendMessage(hTip, TTM_SETTITLE, nIcon, txt.ptr)
buf.Zero()
# TTF_TRACK | TTF_ABSOLUTE | TTF_PARSELINKS
buf.SetNum(0, "uint", buf.size, "uint", 0x10a0, "hwnd", hTip)
buf.SetNum(auX64 ? 48 : 36, "ptr", txt.ptr)
SendMessage(hTip, TTM_ADDTOOL, 0, buf.ptr)
SendMessage(hTip, TTM_SETMAXTIPWIDTH, 0, nMaxWidth)
EndIf
If sText = "" Then
SendMessage(hTip, TTM_TRACKACTIVATE, 0, buf.ptr)
Return hTip
EndIf
# additional menu items
gTipMenuItems = sMenuItems
# cartoon or square
Local op = (BitAND(nFlags, 2) ? 4 : 2)
WinSetStyle(0x0000040, op, hTip)
txt.Zero()
txt.SetStr(sTitle & Chr(0))
SendMessage(hTip, TTM_SETTITLE, nIcon, txt.ptr)
txt.Zero()
txt.SetStr(sText & Chr(0))
# the next call won't fail if the tip is not visible
If WinGetState(2, hTip) = 0 Then
SendMessage(hTip, TTM_TRACKACTIVATE, 0, buf.ptr)
EndIf
SendMessage(hTip, TTM_UPDATETIPTEXT, 0, buf.ptr)
SendMessage(hTip, TTM_TRACKACTIVATE, 1, buf.ptr)
WinGetPos("x", "y", "w", "h", hTip)
# the tip will appear at the mouse pointer by default
If Not BitAND(nFlags, 1) Then MouseGetPos("x","y")
# preventing the tip from going off screen
If x + w > SYSINFO_DESKTOPWIDTH Then x = SYSINFO_DESKTOPWIDTH - w
If y + h > SYSINFO_DESKTOPHEIGHT Then y = SYSINFO_DESKTOPHEIGHT - h
SendMessage(hTip, TTM_TRACKPOSITION, 0, MakeInt(x, y, 0))
gTipX = x
gTipY = y
If Not BitAND(nFlags, 4) Then WinSetState(23, hTip)
Return hTip
EndFunc
Func tipwp(hWnd, uMsg, wParam, lParam)
Static MK_LBUTTON = 0x0001, TTM_TRACKPOSITION = 1042
Static DragWidth = GetSystemMetrics(68) #SM_CXDRAG
Static DragHeight = GetSystemMetrics(69) #SM_CYDRAG
Static IsDrag = 0, StartX = 0, StartY = 0
Local x, y
Static tx, ty, buf = Buffer(8)
#OutputDebugString("uMsg " & uMsg)
Switch uMsg
Case 0x004E # WM_NOTIFY
Static tag = 16 + _
48*2 + _
(2048 + 32 + 3)*2
hdr = Buffer(tag + (auX64 ? 24 : 12), lParam)
code = hdr.GetNum(auX64 ? 16 : 8, "uint")
If code = 0xFFFFFDF5 Then
link = hdr.GetStr(auX64 ? 136 : 124)
If StrPos(link, "://") Then
# MsgBox("Open the link?" & auCRLF & auCRLF & link, "Autorun", 3+32+0+262144)
# If EXTENDED <> 6 Then Return
ShellExec(link)
Else
Eval(link)
EndIf
EndIf
Case 0x0018 # WM_SHOWWINDOW
If wParam = 0 Then gTipMenuItems = ""
Case 0x0201 # WM_LBUTTONDOWN
If IsDrag = 0 Then
buf.Zero()
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
StartX = x
StartY = y
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
tx = buf.GetNum(0)
ty = buf.GetNum(4)
IsDrag = 1
DllCall("SetCapture", "hwnd", hWnd, "hwnd")
EndIf
Case 0x0202 # WM_LBUTTONUP
If IsDrag = 1 Then
WinGetPos("gTipX", "gTipY", "", "", hWnd)
IsDrag = 0
DllCall("ReleaseCapture")
EndIf
Case 0x0200 # WM_MOUSEMOVE
If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
If Abs(x - startX) > DragWidth Or Abs(y - startY) > DragHeight Then
buf.Zero()
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
x = buf.GetNum(0)
y = buf.GetNum(4)
SendMessage(hWnd, TTM_TRACKPOSITION, 0, MakeInt(gTipX+(x-tx), gTipY+(y-ty), 0))
EndIf
EndIf
Case 0x0205 # WM_RBUTTONUP
gTipText = WinGetText(hWnd)
ShowPopupMenu /D /F /I:0 "tipmnu"
Case 0x0100 # WM_KEYDOWN
If wParam = 0x1B Then WinSetState(0, hWnd)
EndSwitch
Return DllCall("CallWindowProcW", _
"ptr", gTipWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc
Func tipmnu()
Local txt
txt &= 'MENUITEM "Copy text", em_aucmd ' & (gTipText <> "" ? "" : "/D") & ' -1 tipcopy' & auCRLF
If gTipMenuItems <> "" Then
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= gTipMenuItems
EndIf
Return txt
EndFunc
Func tipcopy()
#ClipPut %"gTipText"
ClipPut(gTipText)
EndFunc |
Если в тексте есть гиперссылки, созданные стандартным тегом <a ref>, они будут открываться в браузере. Пример | Code: | <a href="www.example.com">Link</a> | Клики по ссылкам, конечно, еще открывают некоторые возможности. Например, можно сделать что-то вроде советчика, который будет время от времени вызывать окно подсказки, предлагая ознакомиться с той или иной статьей в интернете. Алгоритм такого советчика не должен быть сложным: достаточно загрузить файл, подготовить его к работе, подсчитать количество статей и выбирать переодически соучайный номер с помощью регулярного выражения. Небольшая зарисовка на основе цикла статей www.majorgeeks.com:
 Hidden text
 Hidden text | Code: | RegisterCommand 71120 "HowToUpdate"
Func HowToUpdate()
Static c = 0, i = 0, text
Local link = "https://www.majorgeeks.com"
Local file = TEMP & "\how_to.html", res, txt
If Not FileExist(file) Then
res = WinInetDownloadFile(link & "/content/overview/how_to.html", file)
If res <> 0 Then Return
Sleep(1000)
tip(file, 1, "Processing")
Sleep(500)
txt = FileRead(file)
txt = StrReplace(txt, """, '"')
txt = StrReplace(txt, "'", "'")
txt = StrReplace(txt, "&#039;", "'")
txt = StrReplace(txt, "&", "&")
txt = StrReplace(txt, ">", ">")
txt = StrReplace(txt, "<", "<")
FileWrite(file, txt)
c = 0
EndIf
Local rex
c += 1
If c = 1 Then
i = 0
text = FileRead(file)
rex = RegExp('(<a href="(.*?)">(.*?)</a>)</b><br />\R(.*?)<br />', text)
If rex.Exec() Then
Do
i += 1
Until not rex.ExecNext()
EndIf
Free(rex)
If i = 0 Then
MsgBox("File doesn't contain data " & file, "Autorun", 48)
Return
Else
tip(i & " articles prepared.", 1, "File")
Sleep(1000)
EndIf
EndIf
If i = 0 Then Return tip("No data or corrupt file", 3)
rex = RegExpGet(text, '(<a href="(.*?)">(.*?)</a>)</b><br />\R(.*?)<br />', _
'$4\n<a href="' & link & '/$2">Read more</a>', Random(1, i, 1))
tip(rex, 1)
EndFunc |
А если есть локальный файл, который не нужно загружать с интернета, всё вообще можно свести к 5-6 строкам кода, поскольку количество статей заранее известно (в примере это 2096):
 Hidden text | Code: | Local link = "https://www.majorgeeks.com"
Local file = COMMANDER_PATH & "\Ini\Backup\how-to.html"
Static rex, txt = FileRead(file)
rex = RegExpGet(txt, '(<a href="(.*?)">(.*?)</a>)</b><br />\R(.*?)<br />', _
'$4\n<a href="' & link & '/$2">Read more</a>', Random(1, 2096, 1))
tip(rex, 1) |
Завтра будет еще пара примеров, нужно только кое-какие нюансы утрясти, а так все готово. |
|