#Include "Gra.ch" #Include "Xbp.ch" #Include "Appevent.ch" #Include "Font.ch" *************************** CLASS MagicHelp FROM Thread *************************** HIDDEN: VAR lStop VAR nTipSec VAR cTip VAR aTipSize VAR nColorBG VAR nColorFG VAR nBaseLine VAR nDesktopWidth EXPORTED: VAR oThisXbp VAR oTip VAR lTipIsShown METHOD execute() METHOD showTip() METHOD hideTip() METHOD Paint() INLINE METHOD init() ::lStop := .F. ::lTipIsShown := .f. ::aTipSize := {0, 0} ::nColorBG := GraMakeRGBColor({255, 255, 180}) ::nColorFG := XBPSYSCLR_INFOTEXT ::oTip := XbpStatic():new() ::oTip:type := XBPSTATIC_TYPE_TEXT ::oTip:paint := {|| ::paint()} ::oTip:create(AppDesktop(), AppDesktop(), {0, 0}, {0, 0}, {{XBP_PP_BGCLR, XBPSYSCLR_TRANSPARENT},; {XBP_PP_FGCLR, XBPSYSCLR_TRANSPARENT},; {XBP_PP_COMPOUNDNAME, '10.Arial'}}, .f.) ::nBaseLine := (::oTip:setfont():baseLine - 1) ::nDesktopWidth := AppDesktop():currentSize()[01] Return ::thread:init() ENDCLASS ************************ METHOD MagicHelp:Execute(oClient, nThreadID) ************************ Local lFirst := .t., nEvent, mp1:=0, mp2:=0, oXbp:=NIL Local nStart, nSeconds Sleep(50) Do While !::lStop nEvent := LastAppEvent(@mp1, @mp2, @oXbp, nThreadID) if nEvent == xbeM_Motion if oXbp <> oClient exit endif elseif nEvent == xbeP_Keyboard .or.; nEvent == xbeM_LbDown .or.; nEvent == xbeM_RbDown .or.; nEvent == xbeM_MbDown .or.; nEvent == xbeM_Wheel exit elseif nEvent == xbeM_Leave exit EndIf if lFirst if ::lStop exit endif lFirst := .f. if !::oTip:isVisible() ::oTip:show() endif nStart := Seconds() loop endif nSeconds := (Seconds() - nStart) if nSeconds > 10.0 .or.; nSeconds < 0.0 exit endif Sleep(10) EndDo ::oTip:hide() ::lTipIsShown := .f. ::lStop := .f. Return ************************ METHOD MagicHelp:showTip(aPos, oXbp, cText) ************************ LOCAL oPS, aTipPos, aPoints, nTipWidth If (!::lTipIsShown) ::lTipIsShown := .t. ::lStop := .f. /* * calculate absolute position of motion event and adjust it * about the mouse pointer size */ aTipPos := calcAbsolutePosition(aPos, oXbp) aTipPos[2] -= 30 // Calculating the size of ::oTip ::cTip := cText oPS := ::oTip:lockPS() aPoints := GraQueryTextBox(oPS, cText) nTipWidth := ((aPoints[3,1] - aPoints[1,1]) + 10) if (aTipPos[01] + nTipWidth) > ::nDesktopWidth aTipPos[01] := (::nDesktopWidth - nTipWidth) endif ::aTipSize[1] := nTipWidth ::aTipSize[2] := ((aPoints[1,2] - aPoints[2,2]) + 8) ::oTip:unlockPS() ::oTip:configure(NIL, NIL, aTipPos, ::aTipSize) ::aTipSize[01] -= 2 ::aTipSize[02] -= 2 // Para :paint() ::Thread:start(NIL, oXbp, ThreadID()) EndIf Return ************************ METHOD MagicHelp:hideTip() ************************ If (::lTipIsShown) ::lStop := .T. ::synchronize(0) // Executes :execute() EndIf Return **************************** METHOD MagicHelp:paint() **************************** Local aAreaAttr[GRA_AA_COUNT], aLineAttr[GRA_AL_COUNT],; aStringAttr[GRA_AS_COUNT] Local oPS oPS := ::oTip:lockPS() aAreaAttr[GRA_AA_COLOR] := ::nColorBG aLineAttr [GRA_AL_COLOR] := GRA_CLR_RED GraSetAttrArea(oPS, aAreaAttr) GraSetAttrLine(oPS, aLineAttr) GraBox(oPS, { 0, 0}, ::aTipSize, GRA_OUTLINEFILL, 09, 09) aStringAttr [ GRA_AS_COLOR ]:=::nColorFG GraSetAttrString(oPS, aStringAttr) GraStringAt(oPS, {4,(::nBaseLine + 4)}, ::cTip) ::oTip:unLockPS(oPS) Return(Self) /* * This function calculates the absolute position * from a given position relative to an XbasePART */ ******************************** Static Func CalcAbsolutePosition(aPos, oXbp) ******************************** Local aAbsPos:=AClone(aPos) Local oParent:=oXbp Local oDesktop:=AppDesktop() aAbsPos[02] := oXbp:currentPos()[02] // The "tip" will always to be below oXbp Do While oParent <> oDesktop aAbsPos[1] += oParent:currentPos()[1] aAbsPos[2] += oParent:currentPos()[2] oParent := oParent:setParent() EndDo Return(aAbsPos)