@@ -547,9 +547,11 @@ template iconButton*(image: string, body) =
547547 case interaction
548548 of Hovered :
549549 sk.hover = true
550+ sk.tooltipAnchor = buttonRect
550551 patch = " button.hover.9patch"
551552 of Pressed , Held :
552553 sk.hover = true
554+ sk.tooltipAnchor = buttonRect
553555 patch = " button.down.9patch"
554556 of Released :
555557 sk.hover = false
@@ -583,6 +585,8 @@ template clickableIcon*(image: string, on: bool, body) =
583585 offColor
584586
585587 sk.hover = interaction in [Hovered , Pressed , Held ]
588+ if sk.hover:
589+ sk.tooltipAnchor = iconRect
586590
587591 if interaction == Pressed :
588592 body
@@ -1144,33 +1148,102 @@ template menuItem*(label: string, body: untyped) =
11441148 sk.menuItemEnd (ctx)
11451149
11461150template tooltip * (text: string ) =
1147- # # Display a tooltip at the mouse cursor.
1148- # # This should be called after a widget when sk.showTooltip is true.
1151+ # # Draws a tooltip with fade-in and stem image.
11491152 let tooltipText = text
11501153 sk.pushLayer (PopupsLayer )
11511154 sk.pushRawClipRect (rect (vec2 (0 , 0 ), sk.rootSize))
11521155
1153- let textSize = sk.getTextSize (sk.textStyle, tooltipText)
1154- let tooltipSize = textSize + vec2 (sk.theme.padding.float32 * 2 , sk.theme.padding.float32 * 2 )
1155- let mousePos = sk.mousePos
1156-
1157- # Position tooltip near mouse, offset slightly to avoid cursor.
1158- var tooltipPos = mousePos + vec2 (16 , 16 )
1159-
1160- # Keep tooltip on screen.
1161- let root = sk.rootSize
1162- if tooltipPos.x + tooltipSize.x > root.x:
1163- tooltipPos.x = root.x - tooltipSize.x - sk.theme.padding.float32
1156+ let
1157+ textSize = sk.getTextSize (sk.textStyle, tooltipText)
1158+ pad = sk.theme.padding.float32
1159+ tooltipSize = textSize + vec2 (pad * 2 , pad * 2 )
1160+ root = sk.rootSize
1161+ hasAnchor = sk.tooltipAnchor.w > 0 and
1162+ sk.tooltipAnchor.h > 0
1163+ anchorCenter = sk.tooltipAnchor.xy +
1164+ vec2 (sk.tooltipAnchor.w, sk.tooltipAnchor.h) * 0.5
1165+
1166+ # Position centered on anchor below, flip above if needed.
1167+ var tooltipPos =
1168+ if hasAnchor:
1169+ vec2 (
1170+ anchorCenter.x - tooltipSize.x * 0.5 ,
1171+ sk.tooltipAnchor.y + sk.tooltipAnchor.h + 8
1172+ )
1173+ else :
1174+ sk.mousePos + vec2 (16 , 16 )
1175+ tooltipPos += sk.tooltipOffset
11641176 if tooltipPos.y + tooltipSize.y > root.y:
1165- tooltipPos.y = mousePos.y - tooltipSize.y - 4
1177+ tooltipPos.y = sk.tooltipAnchor.y - tooltipSize.y - 8
1178+ if tooltipSize.x <= root.x:
1179+ tooltipPos.x = clamp (
1180+ tooltipPos.x, pad, root.x - tooltipSize.x - pad)
1181+ if tooltipSize.y <= root.y:
1182+ tooltipPos.y = max (tooltipPos.y, pad)
1183+
1184+ # Reset fade when anchor changes.
1185+ if not sk.tooltipActive or
1186+ sk.tooltipAnchor != sk.tooltipLastAnchor:
1187+ sk.tooltipPos = tooltipPos
1188+ sk.tooltipFadeInTime = 0
1189+ sk.tooltipLastAnchor = sk.tooltipAnchor
1190+ sk.showTooltip = true
11661191
1167- # Ensure tooltip doesn't go off-screen left or top.
1168- tooltipPos.x = max (tooltipPos.x, sk.theme.padding.float32 )
1169- tooltipPos.y = max (tooltipPos.y, sk.theme.padding.float32 )
1192+ let
1193+ fadeAlpha = clamp (
1194+ sk.tooltipFadeInTime / sk.tooltipFadeInDuration,
1195+ 0.0 , 1.0
1196+ ).float32
1197+ fadeByte = (255.0 * fadeAlpha).uint8
1198+ fadeColor = rgbx (fadeByte, fadeByte, fadeByte, fadeByte)
1199+ sk.pushLayout (sk.tooltipPos, tooltipSize)
1200+ sk.draw9Patch (
1201+ " tooltip.9patch" , 6 , sk.pos, sk.size, fadeColor
1202+ )
11701203
1171- sk.pushLayout (tooltipPos, tooltipSize)
1172- sk.draw9Patch (" tooltip.9patch" , 6 , sk.pos, sk.size)
1173- discard sk.drawText (sk.textStyle, tooltipText, sk.pos + vec2 (sk.theme.padding), sk.theme.defaultTextColor)
1204+ # Draw stem on top, pointing toward anchor.
1205+ if hasAnchor and " tooltip.stem" in sk.atlas.entries:
1206+ let
1207+ stem = sk.atlas.entries[" tooltip.stem" ]
1208+ stemW = stem.width.float32
1209+ stemH = stem.height.float32
1210+ halfH = stemH * 0.5
1211+ uvPos = vec2 (stem.x.float32 , stem.y.float32 )
1212+ uv0 = uvPos
1213+ uv1 = uvPos + vec2 (stemW, 0 )
1214+ uv2 = uvPos + vec2 (stemW, stemH)
1215+ uv3 = uvPos + vec2 (0 , stemH)
1216+ colors = [fadeColor, fadeColor, fadeColor]
1217+ above = anchorCenter.y < sk.pos.y + sk.size.y * 0.5
1218+ x = clamp (anchorCenter.x,
1219+ sk.pos.x + stemW * 0.5 ,
1220+ sk.pos.x + sk.size.x - stemW * 0.5 )
1221+ cy =
1222+ if above: sk.pos.y + 1.0
1223+ else : sk.pos.y + sk.size.y - 1.0
1224+ p0 = vec2 (x - stemW * 0.5 , cy - halfH)
1225+ p1 = vec2 (x + stemW * 0.5 , cy - halfH)
1226+ p2 = vec2 (x + stemW * 0.5 , cy + halfH)
1227+ p3 = vec2 (x - stemW * 0.5 , cy + halfH)
1228+ t0 = if above: uv3 else : uv0
1229+ t1 = if above: uv2 else : uv1
1230+ t2 = if above: uv1 else : uv2
1231+ t3 = if above: uv0 else : uv3
1232+ sk.drawTriangle ([p0, p1, p2], [t0, t1, t2], colors)
1233+ sk.drawTriangle ([p0, p2, p3], [t0, t2, t3], colors)
1234+
1235+ let
1236+ baseColor = sk.theme.defaultTextColor
1237+ textColor = rgbx (
1238+ (baseColor.r.float32 * fadeAlpha).uint8 ,
1239+ (baseColor.g.float32 * fadeAlpha).uint8 ,
1240+ (baseColor.b.float32 * fadeAlpha).uint8 ,
1241+ (baseColor.a.float32 * fadeAlpha).uint8 ,
1242+ )
1243+ discard sk.drawText (
1244+ sk.textStyle, tooltipText,
1245+ sk.pos + vec2 (sk.theme.padding), textColor
1246+ )
11741247 sk.popLayout ()
11751248
11761249 sk.popClipRect ()
0 commit comments