teadrinker

Custom tooltip

Feb 18th, 2022 (edited)
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. MyTrayTip := new CustomToolTip({ text: "Hello, World!", title: "traytip", trayTip: true, icon: 1, backColor: 0xFFC141
  2.                                , textColor: 0x50669F, fontName: "Calibri", fontOptions: "s18", timeout: 3000 })
  3. Sleep, 4000
  4. ExitApp
  5.  
  6. class CustomToolTip
  7. {
  8. /*
  9. Options                     Description
  10.  
  11. text, title
  12. x, y                        if not specified, near the cursor
  13. icon                        1 — Info, 2 — Warning, 3 — Error, greater than 3 — HICON
  14. margin                      array [left, top, right, bottom]
  15. transparent, closeButton    true/false
  16. textColor, backColor        both colors must be in the RGB numeric format
  17. fontName, fontOptions       like in GUI
  18. trayTip, isBallon           true/false
  19. timeout                     ms
  20. maxWidth                    default value 600
  21. */
  22.    __New( Options )
  23.    {
  24.       static ttStyles := (TTS_NOPREFIX := 2) | (TTS_ALWAYSTIP := 1), TTS_BALLOON := 0x40, TTS_CLOSE := 0x80
  25.            , TTF_TRACK := 0x20, TTF_ABSOLUTE := 0x80
  26.            , TTM_SETMAXTIPWIDTH := 0x418, TTM_TRACKACTIVATE := 0x411, TTM_TRACKPOSITION := 0x412
  27.            , TTM_SETTIPBKCOLOR := 0x413, TTM_SETTIPTEXTCOLOR := 0x414, TTM_SETMARGIN := 0x41A
  28.            , TTM_ADDTOOL        := A_IsUnicode ? 0x432 : 0x404
  29.            , TTM_SETTITLE       := A_IsUnicode ? 0x421 : 0x420
  30.            , TTM_UPDATETIPTEXT  := A_IsUnicode ? 0x439 : 0x40C
  31.            , WM_SETFONT := 0x30, WM_GETFONT := 0x31
  32.            , WS_EX_TRANSPARENT := 0x00000020
  33.            , exStyles := (WS_EX_TOPMOST := 0x00000008) | (WS_EX_COMPOSITED := 0x2000000) | (WS_EX_LAYERED := 0x00080000)
  34.            
  35.       dhwPrev := A_DetectHiddenWindows, O := Options
  36.       DetectHiddenWindows, On
  37.       defGuiPrev := A_DefaultGui, lastFoundPrev := WinExist()
  38.       (o.trayTip && o.isBallon := true)
  39.       this.hWnd := hWnd := DllCall("CreateWindowEx", "UInt", exStyles | WS_EX_TRANSPARENT * !!o.transparent, "Str", "tooltips_class32", "Str", ""
  40.                                                    , "UInt", ttStyles | TTS_CLOSE * !!o.closeButton | TTS_BALLOON * !!o.isBallon
  41.                                                    , "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr")
  42.       WinExist("ahk_id" . hWnd)
  43.       if (o.textColor != "" || o.backColor != "") {
  44.          (o.backColor = "" && o.backColor := 0xFFFFFF)
  45.          DllCall("UxTheme\SetWindowTheme", "Ptr", hWnd, "Ptr", 0, "Str", "")
  46.          ByteSwap := Func("DllCall").Bind("msvcr100\_byteswap_ulong", "UInt")
  47.          SendMessage, TTM_SETTIPBKCOLOR  , ByteSwap.Call(o.backColor << 8)
  48.          SendMessage, TTM_SETTIPTEXTCOLOR, ByteSwap.Call(o.textColor << 8)
  49.       }
  50.       if (o.fontName || o.fontOptions) {
  51.          Gui, New
  52.          Gui, Font, % o.fontOptions, % o.fontName
  53.          Gui, Add, Text, hwndhText
  54.          SendMessage, WM_GETFONT,,,, ahk_id %hText%
  55.          SendMessage, WM_SETFONT, ErrorLevel
  56.          Gui, Destroy
  57.          Gui, %defGuiPrev%: Default
  58.       }
  59.       if o.trayTip {
  60.          try Loc := this.TrackTrayIcon.GetTrayIconLocation()
  61.          o.x := Loc.x + Loc.w//2
  62.          o.y := Loc.y + 4
  63.       }
  64.       if (o.x = "" || o.y = "")
  65.          DllCall("GetCursorPos", "Int64P", pt)
  66.       (o.x = "" && o.x := (pt & 0xFFFFFFFF) + 15), (o.y = "" && o.y := (pt >> 32) + 15)
  67.      
  68.       if IsObject(o.margin) {
  69.          VarSetCapacity(RECT, 16, 0)
  70.          for k, v in o.margin
  71.             NumPut(v, RECT, 4*(A_Index - 1), "UInt")
  72.          SendMessage, TTM_SETMARGIN,, &RECT
  73.       }
  74.       VarSetCapacity(TOOLINFO, sz := 24 + A_PtrSize*6, 0)
  75.       NumPut(sz, TOOLINFO)
  76.       NumPut(TTF_TRACK | TTF_ABSOLUTE * !o.isBallon, TOOLINFO, 4)
  77.       NumPut(ObjGetAddress(Options, "text"), TOOLINFO, 24 + A_PtrSize*3)
  78.      
  79.       SendMessage, TTM_SETTITLE      , o.icon, ObjGetAddress(Options, "title")
  80.       SendMessage, TTM_TRACKPOSITION ,       , o.x | (o.y << 16)
  81.       SendMessage, TTM_SETMAXTIPWIDTH,       , o.maxWidth ? o.maxWidth : 600
  82.       SendMessage, TTM_ADDTOOL       ,       , &TOOLINFO
  83.       SendMessage, TTM_UPDATETIPTEXT ,       , &TOOLINFO
  84.       SendMessage, TTM_TRACKACTIVATE ,  true , &TOOLINFO
  85.      
  86.       if o.trayTip
  87.          TrackingTray := new this.TrackTrayIcon(hWnd)
  88.      
  89.       if o.timeout {
  90.          this.timeoutTimer := Timer := Func("DllCall").Bind("DestroyWindow", "Ptr", hWnd)
  91.          SetTimer, % Timer, % "-" . o.timeout
  92.       }
  93.       WinExist("ahk_id" . lastFoundPrev)
  94.       DetectHiddenWindows, % dhwPrev
  95.    }
  96.    
  97.    UpdateText(newText) {
  98.       static TTM_UPDATETIPTEXT := A_IsUnicode ? 0x439 : 0x40C
  99.       VarSetCapacity(TOOLINFO, sz := 24 + A_PtrSize*6, 0)
  100.       NumPut(sz, TOOLINFO)
  101.       NumPut(&newText, TOOLINFO, 24 + A_PtrSize*3)
  102.       SendMessage, TTM_UPDATETIPTEXT,, &TOOLINFO,, % "ahk_id" . this.hWnd
  103.    }
  104.    
  105.    class TrackTrayIcon {
  106.       __New(hToolTip) {
  107.          Timer := ObjBindMethod(this, "TrackingTray", hToolTip)
  108.          SetTimer, % Timer, 100
  109.       }
  110.       TrackingTray(hToolTip) {
  111.          static x_prev := 0, y_prev := 0
  112.          if !WinExist("ahk_id " . hToolTip) {
  113.             SetTimer,, Delete
  114.             Return
  115.          }
  116.          try Loc := this.GetTrayIconLocation()
  117.          x := Loc.x + Loc.w//2
  118.          y := Loc.y + 4
  119.          if (x != x_prev || y != y_prev) {
  120.             SendMessage, TTM_TRACKPOSITION := 0x412,, x | (y << 16)
  121.             x_prev := x, y_prev := y
  122.          }
  123.       }
  124.       GetTrayIconLocation(hWnd := 0, uID := 0x404) {
  125.          (!hWnd && hWnd := A_ScriptHwnd)
  126.          VarSetCapacity(NOTIFYICONIDENTIFIER, sz := A_PtrSize*3 + 16, 0)
  127.          NumPut(  sz  , NOTIFYICONIDENTIFIER)
  128.          NumPut( hWnd , NOTIFYICONIDENTIFIER, A_PtrSize)
  129.          NumPut( uID  , NOTIFYICONIDENTIFIER, A_PtrSize*2)
  130.  
  131.          VarSetCapacity(RECT, 16, 0)
  132.          hr := DllCall("Shell32\Shell_NotifyIconGetRect", "Ptr", &NOTIFYICONIDENTIFIER, "Ptr", &RECT)
  133.          if (hr != 0)
  134.             throw "Failed to get tray icon location"
  135.          else {
  136.             x := NumGet(RECT, "UInt")
  137.             y := NumGet(RECT, 4, "UInt")
  138.             w := NumGet(RECT, 8, "UInt") - x
  139.             h := NumGet(RECT, 12, "UInt") - y
  140.             Loc := {x: x, y: y, w: w, h: h}
  141.          }
  142.          Return Loc
  143.       }
  144.    }
  145.    
  146.    __Delete() {
  147.       DllCall("DestroyWindow", "Ptr", this.hWnd)
  148.       if this.timeoutTimer {
  149.          Timer := this.timeoutTimer
  150.          try SetTimer, % Timer, Delete
  151.       }
  152.    }
  153. }
Add Comment
Please, Sign In to add comment