Marquee gadget

Share your advanced PureBasic knowledge/code with the community.
Justin
Addict
Addict
Posts: 832
Joined: Sat Apr 26, 2003 2:49 pm

Marquee gadget

Post by Justin »

A module to display marquee text like html.
There is a marquee controller that mantains a list of marquee tools.
You create a marquee controller, usually one for top level window and then add tools to it, it uses a single timer that is only active when any of the tools is scrolling. You handle the window timer event with the built in handler, see example.
You can set colors, font, speed, and horizontal padding. Text is left aligned for now but more options can be added.
Should be crossplatform but just testes on windows.
Image

Code: Select all

DeclareModule guiMarquee
	;- MARQUEE_TOOL_EXINFO
	Structure MARQUEE_TOOL_EXINFO
		LeftPadding.w
		RightPadding.w
		FontID.i
	EndStructure
	
	;- MARQUEE_TOOL
	Structure MARQUEE_TOOL
		*Marquee.MARQUEE
		Canvas.i
		Text.s
		TextX.w
		TextWidth.w
		Scrolling.b
		ClrText.l
		ClrBack.l
		ExInfo.MARQUEE_TOOL_EXINFO
	EndStructure
	
	;- MARQUEE
	Structure MARQUEE
		List Tools.MARQUEE_TOOL()
		TimerID.i
		TimerActive.b
		TimerMS.i
		ParentWindow.i
	EndStructure
	
	;- DECLARES
	Declare Create(parentWindow.i, timerID.i)
	Declare Free(*marquee.MARQUEE)
	Declare CreateTool(*marquee.MARQUEE, x.i, y.i, width.i, height.i, text.s, clrText.l, clrBack.l, *exInfo.MARQUEE_TOOL_EXINFO = #Null)
	Declare DestroyTool(*tool.MARQUEE_TOOL)
	Declare ResizeTool(*tool.MARQUEE_TOOL, x.i, y.i, width.i, height.i)
	Declare HideTool(*tool.MARQUEE_TOOL, hide.b)
	Declare SetToolText(*tool.MARQUEE_TOOL, text.s)
	Declare OnTimerTick(*marquee.MARQUEE)
	Declare SetMiliseconds(*marquee.MARQUEE, ms.i)
EndDeclareModule

Module guiMarquee
	EnableExplicit
	
	Declare DrawTool(*tool.MARQUEE_TOOL)

	#TIMER_MS = 20
	
	Procedure Create(parentWindow.i, timerID.i)
		Define.MARQUEE *this
		
		*this = AllocateStructure(MARQUEE)
		*this\ParentWindow = parentWindow
		*this\TimerID = timerID
		*this\TimerMS = #TIMER_MS
		
		ProcedureReturn *this
	EndProcedure
	
	Procedure Free(*this.MARQUEE)
		ForEach *this\Tools()
			If IsGadget(*this\Tools()\Canvas)
				FreeGadget(*this\Tools()\Canvas)
			EndIf 
		Next 
		FreeList(*this\Tools())
		FreeStructure(*this)
	EndProcedure
	
	Procedure OnToolResize()
		Define.MARQUEE_TOOL *tool
		
		*tool = GetGadgetData(EventGadget())
		If *tool
			DrawTool(*tool)
		EndIf 
	EndProcedure
	
	Procedure CreateTool(*marquee.MARQUEE, x.i, y.i, width.i, height.i, text.s, clrTxt.l, clrBack.l, *exInfo.MARQUEE_TOOL_EXINFO = #Null)
		AddElement(*marquee\Tools())
		*marquee\Tools()\Marquee = *marquee
		*marquee\Tools()\Text = text
		*marquee\Tools()\Canvas = CanvasGadget(#PB_Any, x, y, width, height)
		*marquee\Tools()\ClrText = clrTxt
		*marquee\Tools()\ClrBack = clrBack
		If *exInfo
			CopyMemory(*exInfo, *marquee\Tools()\ExInfo, SizeOf(MARQUEE_TOOL_EXINFO))
			*marquee\Tools()\TextX = *exInfo\LeftPadding
		EndIf 
		
		SetGadgetData(*marquee\Tools()\Canvas, @*marquee\Tools())
		
		BindGadgetEvent(*marquee\Tools()\Canvas, @OnToolResize(), #PB_EventType_Resize)
		
		DrawTool(@*marquee\Tools())
		
		ProcedureReturn @*marquee\Tools()
	EndProcedure
	
	Procedure DrawTool(*tool.MARQUEE_TOOL)
		Define.w txtY
		
		If StartDrawing(CanvasOutput(*tool\Canvas))
			If *tool\ExInfo\FontID <> 0
				DrawingFont(*tool\ExInfo\FontID)
			EndIf 
			
			;Text width is saved here to use it in OnTimerTick().
			*tool\TextWidth = TextWidth(*tool\Text)
			
			;If text is bigger than canvas activate timer
			If *tool\TextWidth > GadgetWidth(*tool\Canvas) - *tool\ExInfo\LeftPadding - *tool\ExInfo\RightPadding
				*tool\Scrolling = #True
				
				If *tool\Marquee\TimerActive = #False
					AddWindowTimer(*tool\Marquee\ParentWindow, *tool\Marquee\TimerID, *tool\Marquee\TimerMS)
					*tool\Marquee\TimerActive = #True 
				EndIf 
				
			Else
				*tool\Scrolling = #False 
				*tool\TextX = 0
			EndIf 
			
			txtY = (GadgetHeight(*tool\Canvas) - TextHeight(*tool\Text)) / 2
			If txtY < 0
				txtY = 0
			EndIf 
			
			Box(0, 0, OutputWidth(), OutputHeight(), *tool\ClrBack)
			DrawingMode(#PB_2DDrawing_Transparent)
			
			;Check Horz Padding
			If *tool\ExInfo\LeftPadding <> 0 Or *tool\ExInfo\RightPadding <> 0
				ClipOutput(*tool\ExInfo\LeftPadding, 0, GadgetWidth(*tool\Canvas) - *tool\ExInfo\LeftPadding - *tool\ExInfo\RightPadding, GadgetHeight(*tool\Canvas))
			EndIf 
			
			DrawText(*tool\TextX + *tool\ExInfo\LeftPadding, txtY, *tool\Text, *tool\ClrText)
			
			StopDrawing()
		EndIf 
	EndProcedure
	
	Procedure OnTimerTick(*marquee.MARQUEE)
		Define.i toolScrolling, canvasWidth
		
		toolScrolling = #False
		
		ForEach *marquee\Tools()
			If *marquee\Tools()\Scrolling = #True
				toolScrolling = #True

				canvasWidth = GadgetWidth(*marquee\Tools()\Canvas)
				
				If *marquee\Tools()\TextX + *marquee\Tools()\TextWidth + *marquee\Tools()\ExInfo\LeftPadding <=  *marquee\Tools()\ExInfo\LeftPadding
					*marquee\Tools()\TextX = canvasWidth - *marquee\Tools()\ExInfo\RightPadding
					
				Else
					*marquee\Tools()\TextX - 1
				EndIf
				
				DrawTool(*marquee\Tools())
			EndIf 
		Next 
		
		;Remove timer if there are no tools scrolling
		If toolScrolling = #False
			RemoveWindowTimer(*marquee\ParentWindow, *marquee\TimerID)
			*marquee\TimerActive = #False
		EndIf 
	EndProcedure
	
	Procedure SetMiliseconds(*marquee.MARQUEE, ms.i)
		*marquee\TimerMS = ms
	EndProcedure
	
	Procedure ResizeTool(*tool.MARQUEE_TOOL, x.i, y.i, width.i, height.i)
		ResizeGadget(*tool\Canvas, x, y, width, height)
	EndProcedure
	
	Procedure SetToolText(*tool.MARQUEE_TOOL, text.s)
		*tool\Text = text
		DrawTool(*tool)
	EndProcedure
	
	Procedure DestroyTool(*tool.MARQUEE_TOOL)
		ForEach *tool\Marquee\Tools()
			If *tool = @*tool\Marquee\Tools()
				FreeGadget(*tool\Marquee\Tools()\Canvas)
				DeleteElement(*tool\Marquee\Tools())
				Break
			EndIf 
		Next 
	EndProcedure
	
	Procedure HideTool(*tool.MARQUEE_TOOL, hide.b)
		HideGadget(*tool\Canvas, hide)
	EndProcedure
EndModule

;- TEST
EnableExplicit

Global.i g_win, g_marquee, g_mt1, g_mt2, g_mt3

#MARQUEE_TIMER_ID = 1

Procedure TimerEvent()
	If EventTimer() = #MARQUEE_TIMER_ID
		guiMarquee::OnTimerTick(g_marquee)
	EndIf 
EndProcedure

Procedure SizeEvent()
	guiMarquee::ResizeTool(g_mt3, #PB_Ignore, #PB_Ignore, WindowWidth(g_win), #PB_Ignore)
EndProcedure

Define.guiMarquee::MARQUEE_TOOL_EXINFO exInfo

g_win = OpenWindow(#PB_Any, 10, 10, 400, 300, "Marquee", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
g_marquee = guiMarquee::Create(g_win, #MARQUEE_TIMER_ID)
BindEvent(#PB_Event_Timer, @TimerEvent(), g_win)
BindEvent(#PB_Event_SizeWindow, @SizeEvent(), g_win)

g_mt1 = guiMarquee::CreateTool(g_marquee, 10, 10, 100, 30, "very long large big test", RGB(255, 255, 255), RGB(0, 0, 0))
g_mt2 = guiMarquee::CreateTool(g_marquee, 10, 50, 120, 30, "very long large big test", RGB(255, 0, 0), RGB(0, 255, 255))

exInfo\LeftPadding = 8
exInfo\RightPadding = 8
exInfo\FontID = FontID(LoadFont(#PB_Any, "Verdana", 10))
g_mt3 = guiMarquee::CreateTool(g_marquee, 0, 150, WindowWidth(g_win), 30, "very long large big padded test", RGB(255, 0, 0), RGB(0, 255, 255), exInfo)

Repeat
	
Until WaitWindowEvent() = #PB_Event_CloseWindow

guiMarquee::Free(g_marquee)
Edit: Bug fix.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5357
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Marquee gadget

Post by Kwai chang caine »

Works perfectly on W7 X86 :D
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
RSBasic
Moderator
Moderator
Posts: 1218
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: Marquee gadget

Post by RSBasic »

Very nice. Image
Image
Image
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Marquee gadget

Post by davido »

Looks good. Works on the Mac, too. :D
DE AA EB
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: Marquee gadget

Post by JHPJHP »

Hi Justin,

Tested in Ubuntu 17.10 and Windows 10; works great (better accuracy in Windows)...

very long large big padded text
- Ubuntu 17.10: started scrolling when the window was resized to the word padded
- Windows 10: started scrolling when the window was resized to the word text
Karellen
User
User
Posts: 82
Joined: Fri Aug 16, 2013 2:52 pm
Location: Germany

Re: Marquee gadget

Post by Karellen »

Nice one! Works very well here, thanks, Justin! :)
Stanley decided to go to the meeting room...
Post Reply