FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour Toast Alert vs (my) TdesktopAlert
Posts: 7318
Joined: Thu Oct 18, 2012 07:17 PM
Toast Alert vs (my) TdesktopAlert
Posted: Fri Apr 01, 2016 05:07 PM
Dear Antonio,
I saw the class of Cristobal called Toast but when I asked you to help me create the Desktop Alert class I showed you it was the alert window

(http://help.infragistics.com/Help/Doc/W ... Alert.html)




As you can see it is totally different with the one created by Cristobal.

Cristobal is good no doubt, but the desktop alert has another design style

I was trying to do all of these features



My class TDesktopAlert approaches the type of Desktop Alert that makes window and now it also allows the animation, up from the bottom and back down after n seconds


the menu can be customized by the user with this command

oAlert:aMnuUser := { {"Option1", { || MsgInfo("1") } },;
{"Option2", { || MsgInfo("2") } } }



to create the animation you need to enter this command

oAlert:Move_Alert(4)

this is the class

sample test.prg

Code (fw): Select all Collapse
#include "FiveWin.ch"

//----------------------------------------------------------------------------//

function Main()

聽 聽local oWnd

聽 聽DEFINE WINDOW oWnd TITLE "Click me for a desktop notification"

聽 聽ACTIVATE WINDOW oWnd ;
聽 聽 聽 聽 聽 ON CLICK ShowAlert()

return nil

//----------------------------------------------------------------------------//

function ShowAlert( oWnd )

聽 聽local oAlert := TDesktopAlert():New( 100, 100, 450, 160, oWnd, .T.,nRgb( 221, 236, 253 ), nRgb( 95, 131, 179 ) )

聽 聽oAlert:cHeader 聽= "Desktop alert"
聽 聽oAlert:cBody 聽 聽= "This a sample text area."+CRLF+"This a sample text area."
聽 聽oAlert:cFoot 聽 聽= "this is the footer area"

聽 聽oAlert:cBmpHeader = "C:\work\fwh\bitmaps\16x16\help.bmp"
聽 聽oAlert:cBmpFoot 聽 = "C:\work\fwh\bitmaps\16x16\help.bmp"
聽 聽oAlert:cBmpLeft 聽 = "C:\work\fwh\bitmaps\16x16\mail.bmp"

聽 聽oAlert:lLineHeader = .T.
聽 聽oAlert:lBorder 聽 聽 = .T.


聽 聽oAlert:lBtnClose 聽 = .T.
聽 聽oAlert:lBtnDown 聽 聽= .T.
聽 聽oAlert:lSplitHdr 聽 = .T.

聽 聽oAlert:aMnuUser 聽:= { 聽{"Option1", { || MsgInfo("1") } },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽{"Option2", { || MsgInfo("2") } } 聽 }


聽 聽oAlert:Move_Alert(4)

return nil



the last release of My TDesktop Class (created from Ttooltip of Paco)

Code (fw): Select all Collapse
 
#include "fivewin.ch"
#include "Slider.ch"
#include "constant.ch"


#define CW_USEDEFAULT 聽 聽 聽32768
#define SRCCOPY 13369376

#define DT_TOP 聽 聽 聽 聽 聽 聽 聽0x00000000
#define DT_LEFT 聽 聽 聽 聽 聽 聽 0x00000000
#define DT_CENTER 聽 聽 聽 聽 聽 0x00000001
#define DT_RIGHT 聽 聽 聽 聽 聽 聽0x00000002
#define DT_VCENTER 聽 聽 聽 聽 聽0x00000004
#define DT_BOTTOM 聽 聽 聽 聽 聽 0x00000008
#define DT_WORDBREAK 聽 聽 聽 聽0x00000010
#define DT_SINGLELINE 聽 聽 聽 0x00000020
#define DT_EXPANDTABS 聽 聽 聽 0x00000040
#define DT_TABSTOP 聽 聽 聽 聽 聽0x00000080
#define DT_NOCLIP 聽 聽 聽 聽 聽 0x00000100
#define DT_EXTERNALLEADING 聽0x00000200
#define DT_CALCRECT 聽 聽 聽 聽 0x00000400
#define DT_NOPREFIX 聽 聽 聽 聽 0x00000800
#define DT_INTERNAL 聽 聽 聽 聽 0x00001000

#define CS_DROPSHADOW 聽 聽 聽 0x00020000


//=========================================================================
//
// File: 聽 聽test6
// Created:
//
// Project: desktop Alert
//
//=========================================================================



#include "FiveWin.ch"

//----------------------------------------------------------------------------//

function Main()

聽 聽local oWnd

聽 聽DEFINE WINDOW oWnd TITLE "Click me for a desktop notification"

聽 聽ACTIVATE WINDOW oWnd ;
聽 聽 聽 聽 聽 ON CLICK ShowAlert()

return nil

//----------------------------------------------------------------------------//

function ShowAlert( oWnd )

聽 聽local oAlert := TDesktopAlert():New( 100, 100, 450, 160, oWnd, .T.,nRgb( 221, 236, 253 ), nRgb( 95, 131, 179 ) )

聽 聽oAlert:cHeader 聽= "Desktop alert"
聽 聽oAlert:cBody 聽 聽= "This a sample text area."+CRLF+"This a sample text area."
聽 聽oAlert:cFoot 聽 聽= "this is the footer area"

聽 聽oAlert:cBmpHeader = "C:\work\fwh\bitmaps\16x16\help.bmp"
聽 聽oAlert:cBmpFoot 聽 = "C:\work\fwh\bitmaps\16x16\help.bmp"
聽 聽oAlert:cBmpLeft 聽 = "C:\work\fwh\bitmaps\16x16\mail.bmp"

聽 聽oAlert:lLineHeader = .T.
聽 聽oAlert:lBorder 聽 聽 = .T.


聽 聽oAlert:lBtnClose 聽 = .T.
聽 聽oAlert:lBtnDown 聽 聽= .T.
聽 聽oAlert:lSplitHdr 聽 = .T.

聽 聽oAlert:aMnuUser 聽:= { 聽{"Option1", { || MsgInfo("1") } },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽{"Option2", { || MsgInfo("2") } } 聽 }


聽 聽oAlert:Move_Alert(4)

return nil

//----------------------------------------------------------------------------//



//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//

CLASS TDesktopAlert FROM TWindow

聽 聽 聽 CLASSDATA lRegistered AS LOGICAL

聽 聽 聽 DATA lSplitHdr 聽 聽AS LOGICAL INIT .f.
聽 聽 聽 DATA lLeft 聽 聽 聽 聽AS LOGICAL INIT .f.

聽 聽 聽 DATA lLineHeader 聽AS LOGICAL INIT .f.
聽 聽 聽 DATA lLineFoot 聽 聽AS LOGICAL INIT .F.
聽 聽 聽 DATA lBorder 聽 聽 聽AS LOGICAL INIT .t.


聽 聽 聽 DATA cHeader 聽 聽 聽AS CHARACTER INIT 聽""
聽 聽 聽 DATA cBmpLeft 聽 聽 AS CHARACTER INIT 聽""
聽 聽 聽 DATA cBody 聽 聽 聽 聽AS CHARACTER INIT 聽""
聽 聽 聽 DATA cBmpFoot 聽 聽 AS CHARACTER INIT 聽""
聽 聽 聽 DATA cFoot 聽 聽 聽 聽AS CHARACTER INIT 聽""
聽 聽 聽 DATA lRightAlignBody AS LOGICAL INIT .F.

聽 聽 聽 DATA cLibHeader
聽 聽 聽 DATA cBmpHeader
聽 聽 聽 DATA cLibLeft
聽 聽 聽 DATA cLibFoot
聽 聽 聽 DATA cTumbNail 聽 聽AS CHARACTER INIT ""
聽 聽 聽 DATA cHeader2 聽 聽 AS CHARACTER INIT 聽space(255)

聽 聽 聽 DATA nClrPane2
聽 聽 聽 DATA nClrBorder 聽 AS NUMERIC INIT 0
聽 聽 聽 DATA nClrSepara1 聽AS NUMERIC INIT RGB(157,188,219)
聽 聽 聽 DATA nClrSepara2 聽AS NUMERIC INIT CLR_WHITE

聽 聽 聽 DATA nClrTextHeader
聽 聽 聽 DATA nClrTextBody
聽 聽 聽 DATA nClrTextFoot

聽 聽 聽 DATA oFontHdr
聽 聽 聽 DATA oFontHdr2
聽 聽 聽 DATA oFontBody
聽 聽 聽 DATA oFontPie

聽 聽 聽 DATA aHeader 聽 AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA aHeader2 聽AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA aBody 聽 聽 AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA aLeft 聽 聽 AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA aRight 聽 聽AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA aFoot 聽 聽 AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA aBtnClose AS ARRAY INIT {0,0,0,0}

聽 聽 聽 DATA nWRadio
聽 聽 聽 DATA nHRadio
聽 聽 聽 DATA nGetColor

聽 聽 聽 DATA aOldPos, nOldRow, nOldCol
聽 聽 聽 DATA hRgn
聽 聽 聽 DATA nMResize

聽 聽 聽 DATA bBmpLeft

聽 聽 聽 DATA nFixWidth
聽 聽 聽 DATA nFixHeight

聽 聽 聽 DATA bOwnerDraw

聽 聽 聽 DATA oTimer, nTimer

聽 聽 聽 DATA lBtnClose 聽 聽 聽 AS LOGICAL INIT .t.
聽 聽 聽 DATA aBtnClose 聽 聽 聽 AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA lOverClose 聽 聽 聽AS LOGICAL INIT .F.
聽 聽 聽 DATA lOverDown 聽 聽 聽 聽AS LOGICAL INIT .F.
聽 聽 聽 DATA aBtndown 聽 聽 聽 聽AS ARRAY INIT {0,0,0,0}
聽 聽 聽 DATA lBtnDown 聽 聽 聽 聽AS LOGICAL INIT .f.

聽 聽 聽 DATA nOver
聽 聽 聽 DATA lAlert 聽 聽 聽 聽 聽AS LOGICAL INIT .t.
聽 聽 聽 DATA nOption
聽 聽 聽 DATA bAction


聽 聽 聽 DATA aItems
聽 聽 聽 DATA aCoors
聽 聽 聽 DATA nLevel
聽 聽 聽 DATA nDuration
聽 聽 聽 DATA aMnuUser 聽 聽 聽AS ARRAY


聽 聽 聽 METHOD New( nTop, nLeft, nWidth, nHeight, oWnd, lDisenio, nClrPane, ;
聽 聽 聽 聽 聽 聽 聽 聽 聽 nClrPane2, nClrText, nWRadio, nHRadio,aItems,nLevel,aMnuUser) CONSTRUCTOR
聽 聽 聽 METHOD Default ()
聽 聽 聽 METHOD Destroy() 聽INLINE ::oFontHdr :End(),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽::oFontHdr2:End(),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽::oFontBody:End(),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽::oFontPie :End(),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽DeleteObject( ::hRgn ),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽::Super:Destroy()
聽 聽 聽 METHOD EndPaint() INLINE ::nPaintCount--,EndPaint( ::hWnd, ::cPS ), ::cPS := nil, ::hDC := nil, 0
聽 聽 聽 METHOD Display() 聽INLINE ::BeginPaint(),::Paint(),::EndPaint(),0
聽 聽 聽 METHOD Paint 聽 ()
聽 聽 聽 METHOD PaintHdr ( hDC, rc )
聽 聽 聽 METHOD PaintHdr2( hDC, rc )
聽 聽 聽 METHOD PaintBody( hDC, rc )
聽 聽 聽 METHOD PaintFoot( hDC, rc )

聽 聽 聽 METHOD HandleEvent( nMsg, nWParam, nLParam )
聽 聽 聽 METHOD ReSize( nSizeType, nWidth, nHeight )
聽 聽 聽 METHOD lHeader() INLINE !empty( ::cHeader )
聽 聽 聽 METHOD lFoot() 聽 INLINE !empty( ::cFoot )
聽 聽 聽 METHOD GetSize()
聽 聽 聽 METHOD SetSize( nWidth, nHeight ) INLINE ::Super:SetSize( nWidth, nHeight, .t. )

聽 聽 聽 METHOD BtnDown( hDC,nTop,nLeft )
聽 聽 聽 METHOD BtnClose( hDC,nTop,nLeft )
聽 聽 聽 METHOD LButtonDown( nRow, nCol, nFlags )
聽 聽 聽 METHOD MouseMove 聽( nRow, nCol, nFlags )
聽 聽 聽 METHOD LButtonUp 聽( nRow, nCol, nFlags )
聽 聽 聽 METHOD GetItems()
聽 聽 聽 METHOD SetItems( aItems )
聽 聽 聽 METHOD PopMenu( nRow, nCol, nKey ) 聽// PopUp menu options
聽 聽 聽 METHOD DesktopAlertSettings
聽 聽 聽 METHOD Move_Alert(nTime)
ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( nTop, nLeft, nWidth, nHeight, oWnd, lDisenio, nClrPane, nClrPane2,;
聽 聽 聽 聽 聽 聽 nClrText, nWRadio, nHRadio,aItems,nLevel,aMnuUser) CLASS TDesktopAlert

聽 聽DEFAULT nClrPane 聽:= CLR_WHITE
聽 聽DEFAULT nClrPane2 := nClrPane
聽 聽DEFAULT nClrText 聽:= 0
聽 聽DEFAULT nWRadio 聽 := 2
聽 聽DEFAULT nHRadio 聽 := 2
聽 聽DEFAULT nLevel 聽 聽 聽:= 180

聽 聽DEFAULT aItems 聽 聽:= {"close","Down"}

聽 ::SetItems( aItems )

聽 聽::oWnd 聽 聽 聽 = oWnd
聽 聽::nStyle 聽 聽 = nOR( WS_POPUP, WS_VISIBLE )
聽 聽::nTop 聽 聽 聽 = nTop
聽 聽::nLeft 聽 聽 聽= nLeft
聽 聽::nBottom 聽 聽= nTop + nHeight
聽 聽::nRight 聽 聽 = nLeft + nWidth

聽 聽::nClrPane 聽 = nClrPane
聽 聽::nClrPane2 聽= nClrPane2
聽 聽::nClrText 聽 = nClrText
聽 聽::nClrBorder = RGB( 118,118,118 )
聽 聽::nWRadio 聽 聽= nWRadio
聽 聽::nHRadio 聽 聽= nHRadio

聽 聽::nTimer 聽 聽 = 5000
聽 聽::nLevel 聽 聽 = nLevel

聽 聽::aBtnClose 聽 聽 聽:= {}
聽 聽::aBtnDown 聽 聽 聽 := {}
聽 聽::aCoors 聽 聽 聽 聽 := {}

聽 聽::aMnuUser 聽 聽 聽 := {}


聽 聽DEFINE FONT ::oFontHdr 聽 NAME "Verdana" 聽SIZE 0, -11 BOLD
聽 聽DEFINE FONT ::oFontHdr2 聽NAME "Verdana" 聽SIZE 0, -11
聽 聽DEFINE FONT ::oFontBody 聽NAME "Segoe UI" SIZE 0, -11
聽 聽DEFINE FONT ::oFontPie 聽 NAME "Verdana" 聽SIZE 0, -11 BOLD

聽 聽::Register( nOR( CS_VREDRAW, CS_HREDRAW, CS_DROPSHADOW ) ) //, 131072

聽 聽::Create()

聽 聽::cTitle = "Desktop Alert"
聽 聽::hRgn 聽 = nil
聽 聽::nOver 聽 聽 聽 聽:= -1

聽 聽::nOption:= 1

聽 聽*::Default( .f. )

聽 聽::Shadow()

聽 聽SetTransparent( self, ::nLevel )

return Self

//----------------------------------------------------------------------------//

METHOD GetSize() CLASS TDesktopAlert

聽 聽local rc 聽 聽 聽 聽:= 0
聽 聽local aSize 聽 聽 := { 0, 0 }
聽 聽local hBmp 聽 聽 聽:= 0
聽 聽local hDC 聽 聽 聽 := 0
聽 聽local hOldFont 聽:= 0
聽 聽local n 聽 聽 聽 聽 := 0
聽 聽local nHBmp 聽 聽 := 0
聽 聽local nHText 聽 聽:= 0
聽 聽local nHeight 聽 := 0
聽 聽local nLen 聽 聽 聽:= 0
聽 聽local nW 聽 聽 聽 聽:= 0
聽 聽local nW2 聽 聽 聽 := 0
聽 聽local nWB 聽 聽 聽 := 0
聽 聽local nWBmp 聽 聽 := 0
聽 聽local nWBodyTxt := 227
聽 聽local nWF 聽 聽 聽 := 0
聽 聽local nWH 聽 聽 聽 := 0
聽 聽local nWidth 聽 聽:= 0

聽 聽 聽if ::nFixWidth != nil .and. ::nFixHeight != nil
聽 聽 聽 聽 return {::nFixWidth, ::nFixHeight}
聽 聽 聽endif

聽 聽 聽rc 聽 聽 聽 聽:= GetClientRect(::hWnd)
聽 聽 聽nWidth 聽 聽:= nWBodyTxt

聽 聽 聽// Header
聽 聽 聽if ! Empty( ::cHeader )
聽 聽 聽 聽 nHeight += 31
聽 聽 聽 聽 nWH = GetTextWidth( 0, ::cHeader, ::oFontHdr:hFont ) + 16
聽 聽 聽endif

聽 聽 聽// Left side image
聽 聽 聽if ! Empty( ::cBmpLeft )
聽 聽 聽 聽 hBmp := LoadImageEx( ::cBmpLeft )
聽 聽 聽else
聽 聽 聽 聽if ::bBmpLeft != nil
聽 聽 聽 聽 聽 hBmp = Eval( ::bBmpLeft, self )
聽 聽 聽 聽endif
聽 聽 聽endif

聽 聽 聽if hBmp != 0
聽 聽 聽 聽 nWBmp := BmpWidth ( hBmp )
聽 聽 聽 聽 nHBmp := BmpHeight( hBmp )
聽 聽 聽 聽 nWidth += ( 14 + nWBmp )
聽 聽 聽 聽 DeleteObject( hBmp )
聽 聽 聽endif

聽 聽 聽if Empty( ::cHeader ) .and. Empty( ::cFoot )
聽 聽 聽 聽 nWidth = 13 + If( nWBmp != 0, ( nWBmp + 13 ), 0 ) + ;
聽 聽 聽 聽 聽 聽 聽 聽 聽GetTextWidth( 0, ::cBody, ::oFontBody:hFont ) + 26

聽 聽 聽endif

聽 聽 聽if ! Empty( ::cFoot )
聽 聽 聽 聽 nHeight += 30
聽 聽 聽 聽 nWF = GetTextWidth( 0, ::cFoot, ::oFontPie:hFont ) + 22
聽 聽 聽endif

聽 聽 聽nWidth = Max( Max( nWidth, nWH ), nWF )

聽 聽 聽if Empty( ::cHeader ) .and. Empty( ::cFoot )
聽 聽 聽 聽 nWidth = Min( nWidth, 227 )
聽 聽 聽endif

聽 聽 聽// if there is text in the body
聽 聽 聽if ! Empty( ::cBody )
聽 聽 聽 聽 hDC 聽 聽 聽= CreateDC( "DISPLAY",0,0,0)
聽 聽 聽 聽 hOldFont = SelectObject( hDC, ::oFontBody:hFont )//
聽 聽 聽 聽 nHText 聽 = DrawText( hDC, AllTrim( ::cBody ),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽{ 0, 12 + nWBmp + 12 + 10, 20, nWidth },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽nOr( DT_WORDBREAK, 8192, DT_CALCRECT ) )
聽 聽 聽 聽 SelectObject( hDC, hOldFont )
聽 聽 聽 聽 DeleteDC( hDC )
聽 聽 聽 聽 nHeight += nHText
聽 聽 聽 聽 nHeight +=8
聽 聽 聽endif

聽 聽 聽nHeight = Max( nHeight, nHBmp )

聽 聽 聽aSize := { nWidth, nHeight }

return aSize

//----------------------------------------------------------------------------//

METHOD Default( lShowDlg ) CLASS TDesktopAlert

聽 聽local rc := {0, 0, ::nHeight, ::nWidth}
聽 聽Local hRgn
聽 聽Local hRgn2
聽 聽Local hRgn3
聽 聽local o := self

DEFAULT lShowDlg := .F.

聽 * o:SetPos( ScreenHeight() - rc[ 3 ], ScreenWidth( 0 ) - rc[ 4 ]-10 )

聽 聽::hRgn = CreateRoundRectRgn( rc[ 2 ], rc[ 1 ], rc[ 4 ], rc[ 3 ], ::nWRadio,;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 ::nHRadio )

聽 聽SetWindowRgn( ::hWnd, ::hRgn, .T. )

聽 聽DeleteObject( ::hRgn )

聽 聽return 0

//----------------------------------------------------------------------------//

METHOD Move_Alert(nTime) CLASS TDesktopAlert
聽 Local 聽oDlgheight := GetSysMetrics(1)
聽 Local otask:= self

聽 聽SndPlaySound( "C:\Work\fwh\sounds\alert.wav", 0 )

聽 聽for i = 1 to 20
聽 聽 聽 聽 oDlgheight := 聽oDlgheight - i
聽 聽 聽 聽oTask:Move( 聽oDlgheight, 100, 聽otask:nWidth, otask:nBottom+100, .t. )
聽 聽 聽 聽SysWait(.02)
聽 聽 next

聽 聽SysWait(nTime)

聽 聽for i = 1 to 40
聽 聽 聽 聽 oDlgheight := 聽oDlgheight + i
聽 聽 聽 聽otask:Move( 聽oDlgheight, 100, 聽otask:nWidth, otask:nBottom+100, .t. )
聽 聽 聽 聽SysWait(.02)
聽 聽next
聽 聽otask:end()
聽 聽return


//----------------------------------------------------------------------------//

METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TDesktopAlert

聽 聽if nMsg == 20
聽 聽 聽 return 1
聽 聽endif

return ::Super:HandleEvent( nMsg, nWParam, nLParam )

//----------------------------------------------------------------------------//

METHOD ReSize( nSizeType, nWidth, nHeight ) CLASS TDesktopAlert

聽 聽::Default()
聽 聽::Refresh()

return ::Super:ReSize( nSizeType, nWidth, nHeight )

//----------------------------------------------------------------------------//

METHOD Paint() CLASS TDesktopAlert

聽 local hDCMem 聽 := CreateCompatibleDC( ::hDC )
聽 local rc 聽 聽 聽 := GetClientRect( ::hWnd )
聽 local hBmpMem 聽:= CreateCompatibleBitmap( ::hDC, rc[ 4 ] - rc[ 2 ],;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 rc[ 3 ] - rc[ 1 ] )
聽 local hOldBmp 聽:= SelectObject( hDCMem, hBmpMem )
聽 local nWRadio 聽:= ::nWRadio
聽 local nHRadio 聽:= ::nHRadio
聽 local nClrText := SetTextColor( hDCMem, ::nClrText )
聽 local hBrush
聽 local hRgn 聽 聽 := CreateRoundRectRgn( rc[ 2 ], rc[ 1 ], rc[ 4 ], rc[ 3 ],;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 ::nWRadio, ::nHRadio )

聽 local nLen
聽 local nH
聽 local o := self
聽 nLen := len( ::aItems )

聽 聽 聽 聽 聽 聽 聽::aCoors := array(nLen)
聽 聽 聽 聽 聽for n := 1 to nLen
聽 聽 聽 聽 聽 聽 聽::aCoors[n] :={0,0,0,0}
聽 聽 聽 聽 聽 聽next




聽 聽if ::oTimer != nil
聽 聽 聽 ::oTimer:Deactivate()
聽 聽 聽 ::oTimer:End()
聽 聽endif

聽 聽 IF ::lAlert

聽 聽DEFINE TIMER ::oTimer INTERVAL ::nTimer ACTION ::Hide() OF Self

聽 聽ACTIVATE TIMER ::oTimer

聽 聽Endif



聽 聽rc[ 3 ]--; rc[ 4 ]--
聽 聽nWRadio += 2
聽 聽nHRadio += 2

聽 VerticalGradient( hDCMem, { rc[ 1 ] - 1, rc[ 2 ], rc[ 3 ], rc[ 4 ] },;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 ::nClrPane, ::nClrPane2 )

聽 if ::bOwnerDraw == nil
聽 聽 聽::PaintHdr( hDCMem, rc )
聽 聽 聽::PaintFoot( hDCMem, rc )
聽 聽 聽::PaintBody( hDCMem, rc )
聽 else
聽 聽 聽Eval( ::bOwnerDraw, hDCMem )
聽 endif



聽 hBrush = CreateSolidBrush( ::nClrBorder )

聽 if ::lBorder
聽 聽 聽FrameRgn( hDCMem, hRgn, hBrush, 1, 1 )
聽 endif

聽 聽 nH 聽 聽 聽:= rc[1]+20

聽 聽if ::lBtnClose
聽 聽 聽 ::BtnClose( hDCMem, (nH/2), rc[4]-12, ::lOverClose )
聽 聽endif

聽 聽if ::lBtnDown
聽 聽 聽 ::BtnDown( hDCMem, (nH/2), rc[4]-26, ::lOverDown )
聽 聽endif


聽 DeleteObject( hBrush )
聽 DeleteObject( hRgn )

聽 SetTextColor( hDCMem, nClrText )

聽 BitBlt( ::hDC, 0, 0, rc[ 4 ] - rc[ 2 ], rc[ 3 ] - rc[ 1 ], hDCMem, 0, 0, SRCCOPY )






聽 SelectObject( hDCMem, hOldBmp )
聽 DeleteDC 聽 聽( hDCMem )
聽 DeleteObject( hBmpMem )

return 0

//----------------------------------------------------------------------------//

METHOD PaintHdr( hDC, rc ) CLASS TDesktopAlert

聽 聽local hBmpHdr
聽 聽local nWBmpHdr := 0
聽 聽local hOldFont
聽 聽local nClrText
聽 聽local lIcon := .f.
聽 聽local nTop
聽 聽local nMode

聽 聽local nWBmpClose := 0
聽 聽local hBmpClose

聽 聽// 25 pixels
聽 聽if ::lHeader

聽 聽 聽 ::aHeader = { rc[ 1 ], rc[ 2 ], rc[ 1 ] + 25, rc[ 4 ] }

聽 聽 聽 if ::lLineHeader
聽 聽 聽 聽 聽Line( hDC, ::aHeader[ 3 ], ::aHeader[ 2 ] + 5, ::aHeader[ 3 ],;
聽 聽 聽 聽 聽 聽 聽 聽::aHeader[ 4 ] - 5, ::nClrSepara1 )
聽 聽 聽 聽 聽Line( hDC, ::aHeader[ 3 ] + 1, ::aHeader[ 2 ] + 5, ::aHeader[ 3 ] + 1,;
聽 聽 聽 聽 聽 聽 聽 聽::aHeader[ 4 ] - 5, ::nClrSepara2 )
聽 聽 聽 endif



聽 聽 聽if ! Empty( ::cBmpHeader )
聽 聽 聽 聽 聽hBmpHdr = LoadImageEx( ::cBmpHeader )
聽 聽 聽 聽 聽if hBmpHdr 聽!= 0
聽 聽 聽 聽 聽 聽 nWBmpHdr = BmpWidth( hBmpHdr )
聽 聽 聽 聽 聽 聽 nTop 聽 聽 = ( ::aHeader[ 1 ] + ;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽( ::aHeader[ 3 ] - ::aHeader[ 1 ] ) / 2 ) - ;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽BmpHeight( hBmpHdr ) / 2
聽 聽 聽 聽 聽 聽 nTop 聽 聽 = Max( nTop, 5 )
聽 聽 聽 聽 聽 聽 DrawMasked( hDC, hBmpHdr, nTop, 5 )
聽 聽 聽 聽 聽 聽 DeleteObject( hBmpHdr )
聽 聽 聽 聽 聽endif
聽 聽 聽 endif




聽 聽 聽 hOldFont = SelectObject( hDC, ::oFontHdr:hFont )

聽 聽 聽 if ::nClrTextHeader != nil
聽 聽 聽 聽 聽nClrText = SetTextColor( hDC, ::nCLrTextHeader )
聽 聽 聽 endif
聽 聽 聽 nMode = SetBkMode( hDC, 1 )

聽 聽 聽 DrawText( hDC, ::cHeader, { ::aHeader[ 1 ], ::aHeader[ 2 ] + 10 + ;
聽 聽 聽 聽 聽 聽 聽 聽 If( hBmpHdr != 0, nWBmpHdr, 0 ), ::aHeader[ 3 ],;
聽 聽 聽 聽 聽 聽 聽 聽 ::aHeader[ 4 ] - 10 }, nOr( DT_VCENTER, DT_SINGLELINE, 8192 ) )

聽 聽 聽 SetBkMode( hDC, nMode )

聽 聽 聽 if ::nClrTextHeader != nil
聽 聽 聽 聽 聽SetTextColor( hDC, nClrText )
聽 聽 聽 endif

聽 聽 聽 SelectObject( hDC, hOldFont )
聽 聽else
聽 聽 聽 ::aHeader 聽:= {rc[1],rc[2],rc[1],rc[4]}
聽 聽endif

return 0

//----------------------------------------------------------------------------//

METHOD PaintHdr2( hDC, rc ) CLASS TDesktopAlert

聽 聽local hOldFont
聽 聽local nClrText

聽 聽::aHeader2 = { ::aHeader[ 3 ], rc[ 2 ], ::aHeader[ 3 ], rc[ 4 ] }

聽 聽if ::lHeader

聽 聽 聽 if ::lSplitHdr
聽 聽 聽 聽 聽::aHeader2 = { ::aHeader[ 3 ], rc[ 2 ], ::aHeader[ 3 ] + 25, rc[ 4 ] }
聽 聽 聽 endif

聽 聽 聽 if ::lLineHeader
聽 聽 聽 聽 聽Line( hDC, ::aHeader2[ 3 ], ::aHeader2[ 2 ] + 5, ::aHeader2[ 3 ],;
聽 聽 聽 聽 聽 聽 聽 聽::aHeader2[ 4 ] - 5, ::nClrSepara1 )
聽 聽 聽 聽 聽Line( hDC, ::aHeader2[ 3 ] + 1, ::aHeader2[ 2 ] + 5, ::aHeader2[ 3 ] + 1,;
聽 聽 聽 聽 聽 聽 聽 聽::aHeader2[ 4 ] - 5, ::nClrSepara2 )
聽 聽 聽 endif

聽 聽 聽 hOldFont = SelectObject( hDC, ::oFontHdr2:hFont )

聽 聽 聽 if ::nClrTextHeader != nil
聽 聽 聽 聽 聽nClrText := SetTextColor( hDC, ::nCLrTextHeader )
聽 聽 聽 endif

聽 聽 聽 if ::lSplitHdr .and. ! Empty( ::cHeader2 )
聽 聽 聽 聽 聽DrawText( hDC, ::cHeader2, { ::aHeader2[ 1 ] + 1, ::aHeader2[ 2 ] + 20,;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽::aHeader2[ 3 ], ::aHeader2[ 4 ] - 2 }, nOR( DT_WORDBREAK, 8192 ) )
聽 聽 聽 endif

聽 聽 聽 if ::nClrTextHeader != nil
聽 聽 聽 聽 聽SetTextColor( hDC, nClrText )
聽 聽 聽 endif

聽 聽 聽 SelectObject( hDC, hOldFont )
聽 endif

return 0

//----------------------------------------------------------------------------//

METHOD PaintBody( hDC, rc ) CLASS TDesktopAlert

聽 聽local hOldFont
聽 聽local nWBmp := 0
聽 聽local nClrText
聽 聽local lIcon := .f.
聽 聽local nMode
聽 聽local hBmpLeft := 0
聽 聽local n
聽 聽local nLen
聽 聽local nW
聽 聽local nW2
聽 聽local aLeft

聽 聽::aLeft = { 0, 0, 0, 0 }

聽 聽::aBody = { ::aHeader[ 3 ] + If( ::lLineHeader, 5, 0 ), rc[ 2 ],;
聽 聽 聽 聽 聽 聽 聽 聽::aFoot[ 1 ], rc[ 4 ] }

聽 聽if Empty( ::cBmpLeft )
聽 聽 聽 ::aLeft = { ::aBody[ 1 ], rc[ 2 ], ::aBody[ 3 ],;
聽 聽 聽 聽 聽 聽 聽 聽 聽 If( ::lLeft, ( rc[ 4 ] - rc[ 2 ] ) * 0.33, rc[ 2 ] ) }
聽 聽else
聽 聽 聽 hBmpLeft = LoadImageEx( ::cBmpLeft )
聽 聽 聽 if hBmpLeft != 0
聽 聽 聽 聽 聽nWBmp = BmpWidth( hBmpLeft )
聽 聽 聽 聽 聽::aLeft = { ::aBody[ 1 ], rc[ 2 ], ::aBody[ 3 ], 12 + nWBmp + 12 }
聽 聽 聽 endif
聽 聽endif

聽 聽if ::bBmpLeft != nil
聽 聽 聽 hBmpLeft = Eval( ::bBmpLeft, self )
聽 聽 聽 if hBmpLeft != 0
聽 聽 聽 聽 聽nWBmp = BmpWidth( hBmpLeft )
聽 聽 聽 聽 聽::aLeft = { ::aBody[ 1 ], rc[ 2 ], ::aBody[ 3 ], 12 + nWBmp + 12 }
聽 聽 聽 endif
聽 聽endif

聽 聽::aRight = { ::aBody[ 1 ] + 3, ::aLeft[ 4 ] + 20, ::aBody[ 3 ] - 3, rc[ 4 ] - 10 }

聽 聽hOldFont = SelectObject( hDC, ::oFontBody:hFont )

聽 聽nMode = SetBkMode( hDC, 1 )

聽 聽DrawText( hDC, AllTrim( ::cBody ), ::aRight,;
聽 聽 聽 聽 聽 聽 聽nOr( If( ::lRightAlignBody, DT_RIGHT, DT_LEFT ), DT_WORDBREAK ) )

聽 聽SetBkMode( hDC, nMode )

聽 聽SelectObject( hDC, hOldFont )

聽 聽if hBmpLeft != 0
聽 聽 聽 DrawMasked( hDC, hBmpLeft, ::aLeft[ 1 ] + 5, ::aLeft[ 2 ] + 12 )
聽 聽 聽 DeleteObject( hBmpLeft )
聽 聽endif

return 0

//----------------------------------------------------------------------------//

METHOD PaintFoot( hDC, rc ) CLASS TDesktopAlert

聽 聽local hOldFont, hBmpFoot
聽 聽local nWFoot := 0
聽 聽local nClrText
聽 聽local lIcon := .f.
聽 聽local nMode

聽 聽if ::lFoot
聽 聽 聽 ::aFoot = { rc[ 3 ] - 30, rc[ 2 ], rc[ 3 ], rc[ 4 ] }
聽 聽 聽 if ! Empty( ::cBmpFoot )
聽 聽 聽 聽 聽::aFoot = { rc[ 3 ] - 30, rc[ 2 ], rc[ 3 ], rc[ 4 ] }
聽 聽 聽 endif
聽 聽 聽 hBmpFoot = LoadImageEx( ::cBmpFoot )
聽 聽 聽 if hBmpFoot != 0
聽 聽 聽 聽 聽nWFoot = BmpWidth( hBmpFoot )
聽 聽 聽 聽 聽::aFoot = { rc[ 3 ] - 30, rc[ 2 ], rc[ 3 ], rc[ 4 ] }
聽 聽 聽 聽 聽DrawMasked( hDC, hBmpFoot,;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽( ::aFoot[ 1 ] + ( ::aFoot[ 3 ] - ::aFoot[ 1 ] ) / 2 ) - ;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽BmpHeight( hBmpFoot ) / 2, 5 )
聽 聽 聽 聽 聽DeleteObject( hBmpFoot )
聽 聽 聽 endif
聽 聽 else
聽 聽 聽 聽::aFoot = { rc[ 3 ], rc[ 2 ], rc[ 3 ], rc[ 4 ] }
聽 聽 endif

聽 聽 if ::lFoot
聽 聽 聽 聽hOldFont = SelectObject( hDC, ::oFontPie:hFont )
聽 聽 聽 聽if ::nClrTextFoot != nil
聽 聽 聽 聽 聽 nClrText = SetTextColor( hDC, ::nClrTextFoot )
聽 聽 聽 聽endif
聽 聽 聽 聽nMode = SetBkMode( hDC, 1 )
聽 聽 聽 聽DrawText( hDC, ::cFoot, { ::aFoot[ 1 ], ::aFoot[ 2 ] + 10 + nWFoot,;
聽 聽 聽 聽 聽 聽 聽 聽 聽::aFoot[ 3 ], ::aFoot[ 4 ] }, nOr( DT_VCENTER, DT_SINGLELINE, 8192 ) )
聽 聽 聽 聽SetBkMode( hDC, nMode )
聽 聽 聽 聽if ::nClrTextFoot != nil
聽 聽 聽 聽 聽 SetTextColor( hDC, nClrText )
聽 聽 聽 聽endif
聽 聽 聽 SelectObject( hDC, hOldFont )
聽 聽endif

聽 聽Line( hDC, ::aFoot[ 1 ], ::aFoot[ 2 ] + 5, ::aFoot[ 1 ], ::aFoot[ 4 ] - 5,;
聽 聽 聽 聽 聽::nClrSepara1 )
聽 聽Line( hDC, ::aFoot[ 1 ] + 1, ::aFoot[ 2 ] + 5, ::aFoot[ 1 ] + 1,;
聽 聽 聽 聽 聽::aFoot[ 4 ] - 5, ::nClrSepara2 )

聽 聽return 0


//----------------------------------------------------------------------------//
METHOD BtnClose( hDC,nTop,nLeft ) CLASS TDesktopAlert

::aBtnClose := closebutton( hDC, nTop, nLeft, ::lOverClose )
::aItems[1,3] := ::aBtnClose
聽 return 0

//----------------------------------------------------------------------------//
METHOD BtnDown( hDC,nTop,nLeft ) CLASS TDesktopAlert

::aBtndown := DropDownbutton( hDC, nTop, nLeft, ::lOverDown )
::aItems[2,3] := ::aBtndown
return 0

//----------------------------------------------------------------------------//
聽METHOD LButtonDown( nRow, nCol, nFlags ) CLASS TDesktopAlert

聽 聽 if ::lOverClose
聽 聽 聽 聽::End()
聽 聽 endif

聽 聽 聽 if ::lOverDown
聽 聽 聽 聽 聽 聽 ::PopMenu( nRow, nCol, nFlags )
聽 聽 聽 endif

聽 聽 return 0

//----------------------------------------------------------------------------//

METHOD MouseMove 聽( nRow, nCol, nFlags ) CLASS TDesktopAlert

local nOver := ::nOver
local n
local nLen := len(::aCoors)
local lFindclose := .f.
local lFindDown := .f.

for n := 1 to nLen

聽 聽 if PtInRect( nRow, nCol, ::aBtnClose )
聽 聽 聽 聽lFindClose := .t.
聽 聽 聽 聽::nOver := 1
聽 聽 聽 聽if nOver != 1
聽 聽 聽 聽 聽 //::Refresh(.f.)
聽 聽 聽 聽endif
聽 聽 聽 聽exit
聽 聽 endif


聽 聽 聽if PtInRect( nRow, nCol, ::aBtnDown )
聽 聽 聽 聽lFindDown := .t.
聽 聽 聽 聽::nOver := 2
聽 聽 聽 聽if nOver != 2
聽 聽 聽 聽 聽 //::Refresh(.f.)
聽 聽 聽 聽endif
聽 聽 聽 聽exit
聽 聽 endif


next

::lOverClose := ::nOver > 0 .and. PtInRect( nRow, nCol, ::aItems[1,3] )

::lOverDown := ::nOver > 0 .and. PtInRect( nRow, nCol, ::aItems[2,3] )

if lFindClose 聽 聽.or. lFindDown

聽 聽if ::lOverClose 聽.or. ::lOverDown
聽 聽 聽 CursorHand()
聽 聽else
聽 聽 聽 CursorArrow()
聽 聽endif

else
聽 聽::nOver := -1
聽 聽CursorArrow()
endif

if nOver != ::nOver
聽 聽::Refresh(.f.)
endif


return 0
//----------------------------------------------------------------------------//

聽 聽METHOD LButtonUp 聽( nRow, nCol, nFlags ) CLASS TDesktopAlert

/*if ::nOver > 0
聽 聽if ::lOverClose
聽 聽 聽 ::aItems[1,2] := .t.
聽 聽else
聽 聽 聽 ::nOption := ::nOver
聽 聽 聽 if ::bAction != nil
聽 聽 聽 聽 聽eval(::bAction, ::nOption, ::aItems[::nOption,1])
聽 聽 聽 endif
聽 聽endif
聽 聽::Refresh()
endif
*/

return 0


//----------------------------------------------------------------------------//

METHOD PopMenu( nRow, nCol, nKey ) CLASS TDesktopAlert
聽 聽LOCAL oPopup
聽 聽local i
聽 聽local nLen := len( ::aMnuUser )



聽 聽MENU oPopUp POPUP

聽 IF nLen >0
聽 聽 聽 聽For i := 1 to nLen
聽 聽 聽 聽 聽 聽 bAction := 聽::aMnuUser[i][2]
聽 聽 聽 聽 聽 聽MENUITEM RTrim(::aMnuUser[i][1]) BLOCK bAction
聽 聽 聽 聽 Next i
聽 聽 聽 聽 SEPARATOR
聽 聽 聽endif


聽 聽 聽 聽MENUITEM "Desktop Alert Settimgs" ACTION ::DeskTopAlertSettings()
聽 聽ENDMENU


聽 聽ACTIVATE POPUP oPopup OF Self AT nRow, nCol


聽 聽return nil








//----------------------------------------------------------------------------//

聽METHOD SetItems( aItems ) CLASS TDesktopAlert

聽 聽 local n
聽 聽 local nLen

聽 聽 if len(aItems) != 0

聽 聽 聽 聽::aItems := {}

聽 聽 聽 聽for n := 1 to len(aItems)
聽 聽 聽 聽 聽 聽aadd(::aItems, {aItems[n], .f.,{0,0,0,0}} )
聽 聽 聽 聽next

聽 聽 endif

return 0

//----------------------------------------------------------------------------//


聽 METHOD GetItems() CLASS TDesktopAlert

local n
local nLen := len(::aItems)
local aItems := {}

for n := 1 to nLen
聽 聽 if ::aItems[n,2]
聽 聽 聽 聽aadd(aItems, ::aItems[n,1] )
聽 聽 endif
next

return aItems
//----------------------------------------------------------------------------//

METHOD DesktopAlertSettings 聽CLASS TDesktopAlert
聽 聽Local oDlgSettings
聽 聽Local nDuration := ::nTimer
聽 聽Local ntransparency := ::nLevel
聽 聽local oDuration,oTrans
聽 聽Local cText_Duration:= FWString("How long should the desktop alert appear ?" )
聽 聽local cText_transparency:= FWString("How transparency should the desktop be ?")
聽 聽local obtn[3]
聽 聽local oGrp[2]
聽 聽local oSay[4]
聽 聽Local nBottom 聽 := 20
聽 聽Local nRight 聽 聽:= 62
聽 聽Local nWidth := 聽Max( nRight * DLG_CHARPIX_W, 180 )
聽 聽Local nHeight := nBottom * DLG_CHARPIX_H
聽 聽local oThis := self




聽 聽DEFINE DIALOG oDlgSettings 聽SIZE nWidth, nHeight 聽 PIXEL TITLE FWString( "DesktopAlert Settings" )
聽 聽oDlgSettings:lTruePixel := .f.


@ 0, 2 GROUP oGrp[1] PROMPT FWString("Duration ( 0 - 5 seconds )") OF oDlgSettings SIZE 210,48
@ 4, 2 GROUP oGrp[2] PROMPT FWString("Transparency") OF oDlgSettings SIZE 210,51

@ 0.5, 6 SAY oSay[1] PROMPT cText_Duration OF oDlgSettings 聽 SIZE 180,10
@ 4.2, 6 SAY oSay[2] PROMPT cText_transparency OF oDlgSettings SIZE 180,10


@ 22, 20 SLIDER oDuration VAR nDuration OF oDlgSettings ;
聽 聽 聽 聽 聽 聽 聽 聽HORIZONTAL ;
聽 聽 聽 聽 聽 聽 聽 聽RIGHT DIRECTION ;
聽 聽 聽 聽 聽 聽 聽 聽RANGE 1000, 5000 ; 聽// 0 = NO close
聽 聽 聽 聽 聽 聽 聽 聽MARKS 6;
聽 聽 聽 聽 聽 聽 聽 聽EXACT;
聽 聽 聽 聽 聽 聽 聽 聽ON CHANGE 聽oSay[3]:settext(str(nDuration)+FWString("seconds")) ;
聽 聽 聽 聽 聽 聽 聽 聽SIZE 200, 12 PIXEL

聽@ 38, 96 SAY oSay[3] PROMPT 聽str(nDuration)+FWString("seconds") OF oDlgSettings 聽 SIZE 120,10 pixel


@ 80, 20 SLIDER oTrans VAR ntransparency OF oDlgSettings ;
聽 聽 聽 聽 聽 聽 聽 聽HORIZONTAL ;
聽 聽 聽 聽 聽 聽 聽 聽RIGHT DIRECTION ;
聽 聽 聽 聽 聽 聽 聽 聽RANGE 100, 300 ;
聽 聽 聽 聽 聽 聽 聽 聽MARKS 11;
聽 聽 聽 聽 聽 聽 聽 聽EXACT;
聽 聽 聽 聽 聽 聽 聽 聽ON CHANGE 聽 oSay[4]:settext(str(ntransparency)+FWString(" trasparency level")) ;
聽 聽 聽 聽 聽 聽 聽 聽SIZE 200, 12 PIXEL

@ 96, 96 SAY oSay[4] PROMPT 聽str(ntransparency)+FWString(" trasparency level") 聽OF oDlgSettings SIZE 120,10 聽 聽 聽pixel



@ 118, 14 BUTTON obtn[1] PROMPT FWString("&Preview") SIZE 45,12 聽OF oDlgSettings PIXEL 聽 action (::nLevel := ntransparency,oThis:Display())
@ 118, 94 BUTTON obtn[2] PROMPT FWString("&Ok") SIZE 45,12 聽OF oDlgSettings PIXEL 聽 聽 聽 action 聽oDlgSettings:End(IDOK)
@ 118, 164 BUTTON obtn[3] PROMPT FWString("&Cancel") SIZE 45,12 聽OF oDlgSettings PIXEL 聽action 聽oDlgSettings:End(IDCANCEL)



ACTIVATE DIALOG oDlgSettings CENTERED

IF oDlgSettings:nresult == IDOK

聽* 聽msginfo( "Transp. : " + STR( ::nLevel), "Seconds : " + STR( ::nTimer ) )

聽 聽 聽 聽::nTimer := nDuration
聽 聽 聽 聽::nLevel := ntransparency


Endif




return nil

















聽 聽 聽 聽ACTIVATE DIALOG oDlgSettings CENTERED
return nil





//----------------------------------------------------------------------------//
// Functions
//----------------------------------------------------------------------------//

static function Line( hDC, nTop, nLeft, nBottom, nRight, nColor, nWidth )

聽 聽local hPen, hOldPen

聽 聽DEFAULT nColor := CLR_BLACK, nWidth := 1

聽 聽hPen = CreatePen( PS_SOLID, nWidth, nColor )
聽 聽hOldPen = SelectObject( hDC, hPen )

聽 聽MoveTo( hDC, nLeft, nTop )
聽 聽LineTo( hDC, nRight, nTop )

聽 聽SelectObject( hDC, hOldPen )
聽 聽DeleteObject( hPen )

return 0

//----------------------------------------------------------------------------//

Static Function DropDownbutton( hDC, nTop, nLeft, lOver )
local oFont, hOldFont
local aRect
local nMode

// create a 聽arrow down button

DEFAULT lOver := .f.

聽 nMode 聽 聽:= SetBkMode( hDC, 1 )
聽 oFont := TFont():New( "Marlett", 0, -10, .f.,.f.,,,,.f.,.f.,.f., 1 )
聽 hOldFont := SelectObject( hDC, oFont:hFont )
聽 aRect := {nTop,nLeft,nTop+10,nLeft+ 9}
聽 TextOut( hDC, aRect[1]+1, aRect[2], "u" )
聽 SelectObject( hDC, hOldFont 聽)
聽 oFont:End()
聽 SetBkMode( hDC, nMode )
聽 if lOver
聽 聽 聽Box(hDC,aRect)
聽 endif
聽 return aRect

//---------------------------------------------------------------------------//

Static Function closebutton( hDC, nTop, nLeft, lOver )
local oFont, hOldFont
local aRect
local nMode

// create a X button

DEFAULT lOver := .f.

聽 nMode 聽 聽:= SetBkMode( hDC, 1 )
聽 oFont := TFont():New( "Marlett", 0, -10, .f.,.f.,,,,.f.,.f.,.f., 1 )
聽 hOldFont := SelectObject( hDC, oFont:hFont )
聽 aRect := {nTop,nLeft,nTop+10,nLeft+ 9}
聽 TextOut( hDC, aRect[1]+1, aRect[2], "r" )
聽 SelectObject( hDC, hOldFont 聽)
聽 oFont:End()
聽 SetBkMode( hDC, nMode )
聽 if lOver
聽 聽 聽Box(hDC,aRect)
聽 endif
聽 return aRect
//---------------------------------------------------------------------------//


聽 聽 #define GWL_EXSTYLE 聽 -20
聽 聽 #define WS_EX_LAYERED 524288

static function SetTransparent( oDlg,nLevel )

聽 聽DEFAULT 聽 nLevel := 160

聽 聽 聽 聽SetWindowLong( oDlg:hWnd, GWL_EXSTYLE, nOr( GetWindowLong( oDlg:hWnd, GWL_EXSTYLE ), WS_EX_LAYERED ) )

聽 聽 聽 聽SetLayeredWindowAttributes( oDlg:hWnd, 0, nLevel, 2 )

聽 聽 return nil

//---------------------------------------------------------------------------//
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)

I use : FiveWin for Harbour March-April 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
Posts: 6755
Joined: Wed Feb 15, 2012 08:25 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Fri Apr 01, 2016 06:34 PM

Silvio, yes, you are right if you use style office 2007
As we have commented by mail, to the TToast class still has some things to improve
Your class is very good and I like it a lot too, but, I followed these instructions

There are really only 4 styles notification

https://msdn.microsoft.com/es-es/librar ... s/hh761494

https://msdn.microsoft.com/es-es/librar ... mplatetype

Cristobal Navarro

Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noci贸n del tiempo

El secreto de la felicidad no est谩 en hacer lo que te gusta, sino en que te guste lo que haces
Posts: 7318
Joined: Thu Oct 18, 2012 07:17 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 09:24 AM
yes of course, but on the first page I see this :




but it is that of Microsoft say


but on another guide I saw there are buttons and setup, and the toast come in with animation




here there is also the api

https://github.com/tadeuszwojcik/win-notify

api
https://msdn.microsoft.com/en-US/librar ... -snippet-1
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)

I use : FiveWin for Harbour March-April 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
Posts: 6755
Joined: Wed Feb 15, 2012 08:25 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 10:17 AM
Silvio, yes
In testoast, the example appears with the 4 types of notifications
And do not confuse Tiles with Toast

Please, Help me to complete the class
As we have commented, to the TToast class still has some things to improve
Cristobal Navarro

Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noci贸n del tiempo

El secreto de la felicidad no est谩 en hacer lo que te gusta, sino en que te guste lo que haces
Posts: 7318
Joined: Thu Oct 18, 2012 07:17 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 11:31 AM
As I wrote on private mail
here on Windows seven (on win 8 , win10 I have the same errors) your class or toastteat.prg have many error










Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)

I use : FiveWin for Harbour March-April 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
Posts: 7318
Joined: Thu Oct 18, 2012 07:17 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 11:33 AM

I think we must reinit from original ttooltip class... or from antonio's sample test

viewtopic.php?f=3t=32059start=0hilit=desktop+alert

and insert this feature (animation)

viewtopic.php?f=3t=32082

&&&&

Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)

I use : FiveWin for Harbour March-April 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
Posts: 6755
Joined: Wed Feb 15, 2012 08:25 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 11:43 AM
Yes, at moment, try with
For background colors buttons
Code (fw): Select all Collapse
:nClrTextHeader := CLR_WHITE


For error with DATA lBorder
Please replace with lDrawBorder
Cristobal Navarro

Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noci贸n del tiempo

El secreto de la felicidad no est谩 en hacer lo que te gusta, sino en que te guste lo que haces
Posts: 7318
Joined: Thu Oct 18, 2012 07:17 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 11:47 AM
FOUND TaskbarNotifier.cpp

Code (fw): Select all Collapse
// TaskbarNotifier.cpp : implementation file
// By John O'Byrne - 05 July 2002

#include "stdafx.h"
#include "TaskbarNotifier.h"

#define IDT_HIDDEN聽 聽 聽 0
#define IDT_APPEARING聽 聽聽 聽 1
#define IDT_WAITING聽聽 聽 2
#define IDT_DISAPPEARING聽 聽 3

#define TASKBAR_ON_TOP聽 聽 聽 1
#define TASKBAR_ON_LEFT聽聽 聽 2
#define TASKBAR_ON_RIGHT聽 聽 3
#define TASKBAR_ON_BOTTOM聽 聽4

// CTaskbarNotifier

IMPLEMENT_DYNAMIC(CTaskbarNotifier, CWnd)
CTaskbarNotifier::CTaskbarNotifier()
{
聽 聽 m_strCaption="";
聽 聽 m_pWndParent=NULL;
聽 聽 m_bMouseIsOver=FALSE;
聽 聽 m_hSkinRegion=NULL;
聽 聽 m_hCursor=NULL;
聽 聽 m_crNormalTextColor=RGB(133,146,181);
聽 聽 m_crSelectedTextColor=RGB(10,36,106);
聽 聽 m_nSkinHeight=0;
聽 聽 m_nSkinWidth=0;
聽 聽 
聽 聽 m_dwTimeToShow=0;
聽 聽 m_dwTimeToLive=0;
聽 聽 m_dwTimeToHide=0;
聽 聽 m_dwDelayBetweenShowEvents=0;
聽 聽 m_dwDelayBetweenHideEvents=0;
聽 聽 m_nStartPosX=0;
聽 聽 m_nStartPosY=0;
聽 聽 m_nCurrentPosX=0;
聽 聽 m_nCurrentPosY=0;
聽 聽 m_nIncrement=2;
聽 聽 m_nTaskbarPlacement=0;
聽 聽 m_nAnimStatus=IDT_HIDDEN;
聽 聽 m_rcText.SetRect(0,0,0,0);
}

CTaskbarNotifier::~CTaskbarNotifier()
{
聽 聽 // No need to delete the HRGN, 聽SetWindowRgn() owns it after being called
}

int CTaskbarNotifier::Create(CWnd *pWndParent, int nOrder)
{
聽 聽 m_pWndParent = pWndParent;
聽 聽 m_Order = nOrder;
聽 聽 CString strWndClass = AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW),GetSysColorBrush(COLOR_WINDOW),NULL);
聽 聽 return CreateEx(0,strWndClass,NULL,WS_POPUP | WS_EX_TOPMOST, 0, 0, 0, 0, pWndParent->m_hWnd, NULL);
}

void CTaskbarNotifier::SetTextFont(LPCTSTR szFont,int nSize,int nNormalStyle,int nSelectedStyle)
{
聽 聽 LOGFONT lf;
聽 聽 m_myNormalFont.DeleteObject();
聽 聽 m_myNormalFont.CreatePointFont(nSize,szFont);
聽 聽 m_myNormalFont.GetLogFont(&lf);
聽 聽 
聽 聽 // We 聽set the Font of the unselected ITEM
聽 聽 if (nNormalStyle & TN_TEXT_BOLD)
聽 聽 聽 聽 lf.lfWeight = FW_BOLD;
聽 聽 else
聽 聽 聽 聽 lf.lfWeight = FW_NORMAL;
聽 聽 
聽 聽 if (nNormalStyle & TN_TEXT_ITALIC)
聽 聽 聽 聽 lf.lfItalic=TRUE;
聽 聽 else
聽 聽 聽 聽 lf.lfItalic=FALSE;
聽 聽 
聽 聽 if (nNormalStyle & TN_TEXT_UNDERLINE)
聽 聽 聽 聽 lf.lfUnderline=TRUE;
聽 聽 else
聽 聽 聽 聽 lf.lfUnderline=FALSE;

聽 聽 m_myNormalFont.DeleteObject();
聽 聽 m_myNormalFont.CreateFontIndirect(&lf);
聽 聽 
聽 聽 // We set the Font of the selected ITEM
聽 聽 if (nSelectedStyle & TN_TEXT_BOLD)
聽 聽 聽 聽 lf.lfWeight = FW_BOLD;
聽 聽 else
聽 聽 聽 聽 lf.lfWeight = FW_NORMAL;
聽 聽 
聽 聽 if (nSelectedStyle & TN_TEXT_ITALIC)
聽 聽 聽 聽 lf.lfItalic=TRUE;
聽 聽 else
聽 聽 聽 聽 lf.lfItalic=FALSE;
聽 聽 
聽 聽 if (nSelectedStyle & TN_TEXT_UNDERLINE)
聽 聽 聽 聽 lf.lfUnderline=TRUE;
聽 聽 else
聽 聽 聽 聽 lf.lfUnderline=FALSE;

聽 聽 m_mySelectedFont.DeleteObject();
聽 聽 m_mySelectedFont.CreateFontIndirect(&lf);
}

void CTaskbarNotifier::SetTextColor(COLORREF crNormalTextColor,COLORREF crSelectedTextColor)
{
聽 聽 m_crNormalTextColor=crNormalTextColor;
聽 聽 m_crSelectedTextColor=crSelectedTextColor;
聽 聽 RedrawWindow();
}

void CTaskbarNotifier::SetTextRect(RECT rcText)
{
聽 聽 m_rcText=rcText;
}

BOOL CTaskbarNotifier::SetSkin(UINT nBitmapID,short red,short green,short blue)
{
聽 聽 BITMAP bm;
聽 聽 
聽 聽 m_biSkinBackground.DeleteObject();

聽 聽 if (!m_biSkinBackground.LoadBitmap(nBitmapID))
聽 聽 聽 聽 return FALSE;
聽 聽 GetObject(m_biSkinBackground.GetSafeHandle(), sizeof(bm), &bm);
聽 聽 m_nSkinWidth=bm.bmWidth;
聽 聽 m_nSkinHeight=bm.bmHeight;
聽 聽 m_rcText.SetRect(0,0,bm.bmWidth,bm.bmHeight);

聽 聽 if (red!=-1 && green!=-1 && blue!=-1)
聽 聽 {
聽 聽 聽 聽 // No need to delete the HRGN, 聽SetWindowRgn() owns it after being called
聽 聽 聽 聽 m_hSkinRegion=GenerateRegion((HBITMAP)m_biSkinBackground.GetSafeHandle(),(BYTE) red,(BYTE) green,(BYTE) blue);
聽 聽 聽 聽 SetWindowRgn(m_hSkinRegion, true);
聽 聽 }

聽 聽 return TRUE;
}

BOOL CTaskbarNotifier::SetSkin(LPCTSTR szFileName,short red,short green,short blue)
{
聽 聽 BITMAP bm;
聽 聽 HBITMAP hBmp;
聽 聽 
聽 聽 hBmp=(HBITMAP) ::LoadImage(AfxGetInstanceHandle(),szFileName,IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
聽 聽 if (!hBmp)
聽 聽 聽 聽 return FALSE;

聽 聽 m_biSkinBackground.DeleteObject();
聽 聽 m_biSkinBackground.Attach(hBmp);
聽 聽 GetObject(m_biSkinBackground.GetSafeHandle(), sizeof(bm), &bm);
聽 聽 m_nSkinWidth=bm.bmWidth;
聽 聽 m_nSkinHeight=bm.bmHeight;
聽 聽 m_rcText.SetRect(0,0,bm.bmWidth,bm.bmHeight);

聽 聽 if (red!=-1 && green!=-1 && blue!=-1)
聽 聽 {
聽 聽 聽 聽 // No need to delete the HRGN, 聽SetWindowRgn() owns it after being called
聽 聽 聽 聽 m_hSkinRegion=GenerateRegion((HBITMAP)m_biSkinBackground.GetSafeHandle(),(BYTE) red,(BYTE) green,(BYTE) blue);
聽 聽 聽 聽 SetWindowRgn(m_hSkinRegion, true);
聽 聽 }

聽 聽 return TRUE;
}

BOOL CTaskbarNotifier::SetSkin(HBITMAP hd, short red, short green, short blue)
{
聽 聽 if (!hd)
聽 聽 {
聽 聽 聽 聽 return FALSE;
聽 聽 }

聽 聽 BITMAP bm;

聽 聽 m_biSkinBackground.DeleteObject();
聽 聽 m_biSkinBackground.Attach(hd);
聽 聽 GetObject(m_biSkinBackground.GetSafeHandle(), sizeof(bm), &bm);
聽 聽 m_nSkinWidth=bm.bmWidth;
聽 聽 m_nSkinHeight=bm.bmHeight;
聽 聽 m_rcText.SetRect(0,0,bm.bmWidth,bm.bmHeight);

聽 聽 if (red!=-1 && green!=-1 && blue!=-1)
聽 聽 {
聽 聽 聽 聽 // No need to delete the HRGN, 聽SetWindowRgn() owns it after being called
聽 聽 聽 聽 m_hSkinRegion=GenerateRegion((HBITMAP)m_biSkinBackground.GetSafeHandle(),(BYTE) red,(BYTE) green,(BYTE) blue);
聽 聽 聽 聽 SetWindowRgn(m_hSkinRegion, true);
聽 聽 }

聽 聽 return TRUE;
}

void CTaskbarNotifier::Show(LPCTSTR szCaption,DWORD dwTimeToShow,DWORD dwTimeToLive,DWORD dwTimeToHide,int nIncrement)
{
聽 聽 unsigned int nDesktopHeight;
聽 聽 unsigned int nDesktopWidth;
聽 聽 unsigned int nScreenWidth;
聽 聽 unsigned int nScreenHeight;
聽 聽 CRect rcDesktop;

聽 聽 m_strCaption=szCaption;
聽 聽 m_dwTimeToShow=dwTimeToShow;
聽 聽 m_dwTimeToLive=dwTimeToLive;
聽 聽 m_dwTimeToHide=dwTimeToHide;

聽 聽 ::SystemParametersInfo(SPI_GETWORKAREA,0,&rcDesktop,0);
聽 聽 nDesktopWidth=rcDesktop.right-rcDesktop.left;
聽 聽 nDesktopHeight=rcDesktop.bottom-rcDesktop.top;
聽 聽 nScreenWidth=::GetSystemMetrics(SM_CXSCREEN);
聽 聽 nScreenHeight=::GetSystemMetrics(SM_CYSCREEN);

聽 聽 BOOL bTaskbarOnRight=nDesktopWidth<nScreenWidth && rcDesktop.left==0;
聽 聽 BOOL bTaskbarOnLeft=nDesktopWidth<nScreenWidth && rcDesktop.left!=0;
聽 聽 BOOL bTaskBarOnTop=nDesktopHeight<nScreenHeight && rcDesktop.top!=0;
聽 聽 BOOL bTaskbarOnBottom=nDesktopHeight<nScreenHeight && rcDesktop.top==0;
聽 聽 
聽 聽 switch (m_nAnimStatus)
聽 聽 {
聽 聽 聽 聽 case IDT_HIDDEN:
聽 聽 聽 聽 聽 聽 BOOL b;
聽 聽 聽 聽 聽 聽 DWORD dwErr;
聽 聽 聽 聽 聽 聽 b = ShowWindow(SW_SHOW);
聽 聽 聽 聽 聽 聽 if (!b)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 dwErr = GetLastError();
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 if (bTaskbarOnRight)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenShowEvents=m_dwTimeToShow/(m_nSkinWidth/m_nIncrement);聽 
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenHideEvents=m_dwTimeToHide/(m_nSkinWidth/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosX=rcDesktop.right;
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosY=rcDesktop.bottom-m_nSkinHeight * m_Order;
聽 聽 聽 聽 聽 聽 聽 聽 m_nTaskbarPlacement=TASKBAR_ON_RIGHT;
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 else if (bTaskbarOnLeft)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenShowEvents=m_dwTimeToShow/(m_nSkinWidth/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenHideEvents=m_dwTimeToHide/(m_nSkinWidth/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosX=rcDesktop.left-m_nSkinWidth * m_Order;
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosY=rcDesktop.bottom-m_nSkinHeight * m_Order;
聽 聽 聽 聽 聽 聽 聽 聽 m_nTaskbarPlacement=TASKBAR_ON_LEFT;
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 else if (bTaskBarOnTop)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenShowEvents=m_dwTimeToShow/(m_nSkinHeight/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenHideEvents=m_dwTimeToHide/(m_nSkinHeight/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosX=rcDesktop.right-m_nSkinWidth;
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosY=rcDesktop.top-m_nSkinHeight;
聽 聽 聽 聽 聽 聽 聽 聽 m_nTaskbarPlacement=TASKBAR_ON_TOP;
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 else //if (bTaskbarOnBottom)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 // Taskbar is on the bottom or Invisible
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenShowEvents=m_dwTimeToShow/(m_nSkinHeight/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_dwDelayBetweenHideEvents=m_dwTimeToHide/(m_nSkinHeight/m_nIncrement);
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosX = rcDesktop.right-m_nSkinWidth;
聽 聽 聽 聽 聽 聽 聽 聽 m_nStartPosY = rcDesktop.bottom - m_nSkinHeight * m_Order;
聽 聽 聽 聽 聽 聽 聽 聽 m_nTaskbarPlacement=TASKBAR_ON_BOTTOM;
聽 聽 聽 聽 聽 聽 }

聽 聽 聽 聽 聽 聽 m_nCurrentPosX=m_nStartPosX;
聽 聽 聽 聽 聽 聽 m_nCurrentPosY=m_nStartPosY;
聽 聽 
聽 聽 聽 聽 聽 聽 SetTimer(IDT_APPEARING,m_dwDelayBetweenShowEvents,NULL);
聽 聽 聽 聽 聽 聽 break;

聽 聽 聽 聽 case IDT_WAITING:
聽 聽 聽 聽 聽 聽 RedrawWindow();
聽 聽 聽 聽 聽 聽 KillTimer(IDT_WAITING);
聽 聽 聽 聽 聽 聽 SetTimer(IDT_WAITING,m_dwTimeToLive,NULL);
聽 聽 聽 聽 聽 聽 break;

聽 聽 聽 聽 case IDT_APPEARING:
聽 聽 聽 聽 聽 聽 RedrawWindow();
聽 聽 聽 聽 聽 聽 break;

聽 聽 聽 聽 case IDT_DISAPPEARING:
聽 聽 聽 聽 聽 聽 KillTimer(IDT_DISAPPEARING);
聽 聽 聽 聽 聽 聽 SetTimer(IDT_WAITING,m_dwTimeToLive,NULL);
聽 聽 聽 聽 聽 聽 if (bTaskbarOnRight)
聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosX=rcDesktop.right-m_nSkinWidth;
聽 聽 聽 聽 聽 聽 else if (bTaskbarOnLeft)
聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosX=rcDesktop.left;
聽 聽 聽 聽 聽 聽 else if (bTaskBarOnTop)
聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosY=rcDesktop.top;
聽 聽 聽 聽 聽 聽 else //if (bTaskbarOnBottom)
聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosY=rcDesktop.bottom-m_nSkinHeight;
聽 聽 聽 聽 聽 聽 
聽 聽 聽 聽 聽 聽 SetWindowPos(&wndTopMost,m_nCurrentPosX,m_nCurrentPosY,m_nSkinWidth,m_nSkinHeight,SWP_NOOWNERZORDER/* | SWP_NOZORDER*/ | SWP_NOACTIVATE);
聽 聽 聽 聽 聽 聽 RedrawWindow();
聽 聽 聽 聽 聽 聽 break;
聽 聽 }
}

void CTaskbarNotifier::Hide()
{
聽 聽 switch (m_nAnimStatus)
聽 聽 {
聽 聽 聽 聽 case IDT_APPEARING:
聽 聽 聽 聽 聽 聽 KillTimer(IDT_APPEARING);
聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 case IDT_WAITING:
聽 聽 聽 聽 聽 聽 KillTimer(IDT_WAITING);
聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 case IDT_DISAPPEARING:
聽 聽 聽 聽 聽 聽 KillTimer(IDT_DISAPPEARING);
聽 聽 聽 聽 聽 聽 break;
聽 聽 }
聽 聽 MoveWindow(0,0,0,0);
聽 聽 ShowWindow(SW_HIDE);
聽 聽 m_nAnimStatus=IDT_HIDDEN;
}

HRGN CTaskbarNotifier::GenerateRegion(HBITMAP hBitmap, BYTE red, BYTE green, BYTE blue)
{
聽 聽 WORD wBmpWidth,wBmpHeight;
聽 聽 HRGN hRgn, hTmpRgn;

聽 聽 // 24bit pixels from the bitmap
聽 聽 BYTE *pPixels = Get24BitPixels(hBitmap, &wBmpWidth, &wBmpHeight);
聽 聽 if (!pPixels) return NULL;

聽 聽 // create our working region
聽 聽 hRgn = CreateRectRgn(0,0,wBmpWidth,wBmpHeight);
聽 聽 if (!hRgn) { delete pPixels; return NULL; }

聽 聽 DWORD p=0;
聽 聽 for (WORD y=0; y<wBmpHeight; y++)
聽 聽 {
聽 聽 聽 聽 for (WORD x=0; x<wBmpWidth; x++)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 BYTE jRed 聽 = pPixels[p+2];
聽 聽 聽 聽 聽 聽 BYTE jGreen = pPixels[p+1];
聽 聽 聽 聽 聽 聽 BYTE jBlue 聽= pPixels[p+0];

聽 聽 聽 聽 聽 聽 if (jRed==red && jGreen==green && jBlue==blue)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 // remove transparent color from region
聽 聽 聽 聽 聽 聽 聽 聽 hTmpRgn = CreateRectRgn(x,y,x+1,y+1);
聽 聽 聽 聽 聽 聽 聽 聽 CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
聽 聽 聽 聽 聽 聽 聽 聽 DeleteObject(hTmpRgn);
聽 聽 聽 聽 聽 聽 }

聽 聽 聽 聽 聽 聽 // next pixel
聽 聽 聽 聽 聽 聽 p+=3;
聽 聽 聽 聽 }
聽 聽 }

聽 聽 // release pixels
聽 聽 delete pPixels;

聽 聽 // return the region
聽 聽 return hRgn;
}

BYTE* CTaskbarNotifier::Get24BitPixels(HBITMAP pBitmap, WORD *pwWidth, WORD *pwHeight)
{
聽 聽 BITMAP bmpBmp;
聽 聽 LPBITMAPINFO pbmiInfo;
聽 聽 BITMAPINFO bmiInfo;
聽 聽 WORD wBmpWidth, wBmpHeight;

聽 聽 GetObject(pBitmap, sizeof(bmpBmp),&bmpBmp);
聽 聽 pbmiInfo 聽 = (LPBITMAPINFO)&bmpBmp;

聽 聽 wBmpWidth 聽= (WORD)pbmiInfo->bmiHeader.biWidth;
聽 聽 wBmpWidth -= (wBmpWidth%4);
聽 聽 wBmpHeight = (WORD)pbmiInfo->bmiHeader.biHeight;

聽 聽 *pwWidth 聽= wBmpWidth;
聽 聽 *pwHeight = wBmpHeight;
聽 聽 
聽 聽 BYTE *pPixels = new BYTE[wBmpWidth*wBmpHeight*3];
聽 聽 if (!pPixels) return NULL;

聽 聽 HDC hDC =::GetWindowDC(NULL);

聽 聽 bmiInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
聽 聽 bmiInfo.bmiHeader.biWidth = wBmpWidth;
聽 聽 bmiInfo.bmiHeader.biHeight = -wBmpHeight;
聽 聽 bmiInfo.bmiHeader.biPlanes = 1;
聽 聽 bmiInfo.bmiHeader.biBitCount = 24;
聽 聽 bmiInfo.bmiHeader.biCompression = BI_RGB;
聽 聽 bmiInfo.bmiHeader.biSizeImage = wBmpWidth*wBmpHeight*3;
聽 聽 bmiInfo.bmiHeader.biXPelsPerMeter = 0;
聽 聽 bmiInfo.bmiHeader.biYPelsPerMeter = 0;
聽 聽 bmiInfo.bmiHeader.biClrUsed = 0;
聽 聽 bmiInfo.bmiHeader.biClrImportant = 0;

聽 聽 // get pixels from the original bitmap converted to 24bits
聽 聽 int iRes = GetDIBits(hDC,pBitmap,0,wBmpHeight,(LPVOID)pPixels,&bmiInfo,DIB_RGB_COLORS);

聽 聽 // release the device context
聽 聽 ::ReleaseDC(NULL,hDC);

聽 聽 // if failed, cancel the operation.
聽 聽 if (!iRes)
聽 聽 {
聽 聽 聽 聽 delete pPixels;
聽 聽 聽 聽 return NULL;
聽 聽 };

聽 聽 // return the pixel array
聽 聽 return pPixels;
}

BEGIN_MESSAGE_MAP(CTaskbarNotifier, CWnd)
聽 聽 ON_WM_CREATE()
聽 聽 ON_WM_MOUSEMOVE()
聽 聽 ON_WM_DESTROY()
聽 聽 ON_WM_ERASEBKGND()
聽 聽 ON_WM_PAINT()
聽 聽 ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
聽 聽 ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
聽 聽 ON_WM_SETCURSOR()
聽 聽 ON_WM_LBUTTONUP()
聽 聽 ON_WM_TIMER()
END_MESSAGE_MAP()


// CTaskbarNotifier message handlers

int CTaskbarNotifier::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
聽 聽 if (CWnd::OnCreate(lpCreateStruct) == -1)
聽 聽 聽 聽 return -1;

聽 聽 m_hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(32649));
聽 聽 return 0;
}

void CTaskbarNotifier::OnDestroy()
{
聽 聽 CWnd::OnDestroy();

聽 聽 // TODO: Add your message handler code here
}

void CTaskbarNotifier::OnMouseMove(UINT nFlags, CPoint point)
{
聽 聽 TRACKMOUSEEVENT t_MouseEvent;
聽 聽 t_MouseEvent.cbSize 聽 聽 聽= sizeof(TRACKMOUSEEVENT);
聽 聽 t_MouseEvent.dwFlags 聽 聽 = TME_LEAVE | TME_HOVER;
聽 聽 t_MouseEvent.hwndTrack 聽 = m_hWnd;
聽 聽 t_MouseEvent.dwHoverTime = 1;

聽 聽 ::_TrackMouseEvent(&t_MouseEvent);

聽 聽 CWnd::OnMouseMove(nFlags, point);
}

void CTaskbarNotifier::OnLButtonUp(UINT nFlags, CPoint point)
{
聽 聽 m_pWndParent->SendMessage(WM_TASKBARNOTIFIERCLICKED, m_Type, m_AppValue);
聽 聽 Hide();
聽 聽 CWnd::OnLButtonUp(nFlags, point);
}

LRESULT CTaskbarNotifier::OnMouseHover(WPARAM w, LPARAM l)
{
聽 聽 if (m_bMouseIsOver==FALSE)
聽 聽 {
聽 聽 聽 聽 m_bMouseIsOver=TRUE;
聽 聽 聽 聽 RedrawWindow();
聽 聽 }
聽 聽 return 0;
}

LRESULT CTaskbarNotifier::OnMouseLeave(WPARAM w, LPARAM l)
{
聽 聽 if (m_bMouseIsOver==TRUE)
聽 聽 {
聽 聽 聽 聽 m_bMouseIsOver=FALSE;
聽 聽 聽 聽 RedrawWindow();
聽 聽 }
聽 聽 return 0;
}

BOOL CTaskbarNotifier::OnEraseBkgnd(CDC* pDC)
{
聽 聽 CDC memDC;
聽 聽 CBitmap *pOldBitmap;
聽 聽 BITMAP bm;

聽 聽 memDC.CreateCompatibleDC(pDC);
聽 聽 GetObject(m_biSkinBackground.GetSafeHandle(), sizeof(bm), &bm);
聽 聽 pOldBitmap=memDC.SelectObject(&m_biSkinBackground);

聽 聽 pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&memDC,0,0,SRCCOPY);
聽 聽 memDC.SelectObject(pOldBitmap);

聽 聽 return TRUE;
}

void CTaskbarNotifier::OnPaint()
{
聽 聽 CPaintDC dc(this);
聽 聽 CRect rcClient;
聽 聽 CFont *pOldFont;
聽 聽 char *szBuffer;
聽 聽 聽 聽 
聽 聽 if (m_bMouseIsOver)
聽 聽 {
聽 聽 聽 聽 dc.SetTextColor(m_crSelectedTextColor);
聽 聽 聽 聽 pOldFont=dc.SelectObject(&m_mySelectedFont);
聽 聽 }
聽 聽 else
聽 聽 {
聽 聽 聽 聽 dc.SetTextColor(m_crNormalTextColor);
聽 聽 聽 聽 pOldFont=dc.SelectObject(&m_myNormalFont);
聽 聽 }

聽 聽 szBuffer=new char[m_strCaption.GetLength()+10];
聽 聽 strcpy(szBuffer,m_strCaption);

聽 聽 dc.SetBkMode(TRANSPARENT); 
聽 聽 rcClient.DeflateRect(10,20,10,20);
聽 聽 dc.DrawText(szBuffer,-1,m_rcText,DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_END_ELLIPSIS);
聽 聽 
聽 聽 delete[] szBuffer;
聽 聽 dc.SelectObject(pOldFont);
}

BOOL CTaskbarNotifier::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
聽 聽 if (nHitTest == HTCLIENT)
聽 聽 {
聽 聽 聽 聽 ::SetCursor(m_hCursor);
聽 聽 聽 聽 return TRUE;
聽 聽 }
聽 聽 return CWnd::OnSetCursor(pWnd, nHitTest, message);
}

void CTaskbarNotifier::OnTimer(UINT nIDEvent)
{
聽 聽 switch (nIDEvent)
聽 聽 {
聽 聽 聽 聽 case IDT_APPEARING:
聽 聽 聽 聽 聽 聽 m_nAnimStatus=IDT_APPEARING;
聽 聽 聽 聽 聽 聽 switch(m_nTaskbarPlacement)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_BOTTOM:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (m_nCurrentPosY>(m_nStartPosY-m_nSkinHeight))
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosY-=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_APPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 SetTimer(IDT_WAITING,m_dwTimeToLive,NULL);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nAnimStatus=IDT_WAITING;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_TOP:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if ((m_nCurrentPosY-m_nStartPosY)<m_nSkinHeight)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosY+=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_APPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 SetTimer(IDT_WAITING,m_dwTimeToLive,NULL);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nAnimStatus=IDT_WAITING;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_LEFT:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if ((m_nCurrentPosX-m_nStartPosX)<m_nSkinWidth)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosX+=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_APPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 SetTimer(IDT_WAITING,m_dwTimeToLive,NULL);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nAnimStatus=IDT_WAITING;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_RIGHT:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (m_nCurrentPosX>(m_nStartPosX-m_nSkinWidth))
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosX-=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_APPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 SetTimer(IDT_WAITING,m_dwTimeToLive,NULL);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nAnimStatus=IDT_WAITING;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 SetWindowPos(&wndTopMost,m_nCurrentPosX,m_nCurrentPosY,m_nSkinWidth,m_nSkinHeight,SWP_NOOWNERZORDER/* | SWP_NOZORDER*/ | SWP_NOACTIVATE);
聽 聽 聽 聽 聽 聽 //RedrawWindow();
聽 聽 聽 聽 聽 聽 break;

聽 聽 聽 聽 case IDT_WAITING:
聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_WAITING);
聽 聽 聽 聽 聽 聽 SetTimer(IDT_DISAPPEARING,m_dwDelayBetweenHideEvents,NULL);
聽 聽 聽 聽 聽 聽 break;

聽 聽 聽 聽 case IDT_DISAPPEARING:
聽 聽 聽 聽 聽 聽 m_nAnimStatus=IDT_DISAPPEARING;
聽 聽 聽 聽 聽 聽 switch(m_nTaskbarPlacement)
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_BOTTOM:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (m_nCurrentPosY<m_nStartPosY)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosY+=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_DISAPPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 Hide();
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_TOP:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (m_nCurrentPosY>m_nStartPosY)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosY-=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_DISAPPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 Hide();
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_LEFT:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (m_nCurrentPosX>m_nStartPosX)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosX-=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_DISAPPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 Hide();
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 聽 聽 case TASKBAR_ON_RIGHT:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (m_nCurrentPosX<m_nStartPosX)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 m_nCurrentPosX+=m_nIncrement;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 KillTimer(IDT_DISAPPEARING);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 Hide();
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 break;
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 SetWindowPos(&wndTopMost,m_nCurrentPosX,m_nCurrentPosY,m_nSkinWidth,m_nSkinHeight,SWP_NOOWNERZORDER/* | SWP_NOZORDER*/ | SWP_NOACTIVATE);
聽 聽 聽 聽 聽 聽 //RedrawWindow();
聽 聽 聽 聽 聽 聽 break;
聽 聽 }

聽 聽 CWnd::OnTimer(nIDEvent);
}
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)

I use : FiveWin for Harbour March-April 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
Posts: 6755
Joined: Wed Feb 15, 2012 08:25 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 11:50 AM

Yes,
I saw also the example I built with Visual Studio
That's the ideal solution, but there is much work to convert Fivewin

https://code.msdn.microsoft.com/windows ... e-52eeba29

Cristobal Navarro

Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noci贸n del tiempo

El secreto de la felicidad no est谩 en hacer lo que te gusta, sino en que te guste lo que haces
Posts: 6755
Joined: Wed Feb 15, 2012 08:25 PM
Re: Toast Alert vs (my) TdesktopAlert
Posted: Sat Apr 02, 2016 04:11 PM
Any idea to get this look?
For with the TCalenda control it is not well
Or
Someone has a different calendar control or as set TCalenda with a size larger


Cristobal Navarro

Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noci贸n del tiempo

El secreto de la felicidad no est谩 en hacer lo que te gusta, sino en que te guste lo que haces

Continue the discussion