Scrolling Text Simple - Module - DPI aware - All OS

Share your advanced PureBasic knowledge/code with the community.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Scrolling Text Simple - Module - DPI aware - All OS

Post by Saki »

Scrolling Text Simple - Module - DPI aware - All OS

Since there are always requests for ScrollText, I have made a small module,
which solves this problem very simple. :wink:

Have fun with it

Code: Select all

DeclareModule ScrollingTextSimple_BF
  EnableExplicit
  Declare CreateTextImageSimple_BF(text$, font_ID, text_color=#Black, background_color=#White)
  Declare ScrollTextImageSimple_BF(image_ID, step_width=1)
EndDeclareModule

Module ScrollingTextSimple_BF
  ; Text scrolling - By Saki - DPI aware - This is a part from GFX_Wizzard_BF
  Procedure CreateTextImageSimple_BF(text$, font_ID, text_color=#Black, background_color=#White)
    Protected image_ID=CreateImage(#PB_Any, 16, 16, 24, background_color)
    If Not image_ID : ProcedureReturn 0 : EndIf
    If Not StartDrawing(ImageOutput(image_ID)) : FreeImage(image_ID) : ProcedureReturn 0 : EndIf
    DrawingFont(FontID(font_ID))
    Protected text_width=TextWidth(text$)
    Protected text_height=TextHeight(text$)
    StopDrawing()
    ResizeImage(image_ID, text_width, text_height*1.2)
    StartDrawing(ImageOutput(image_ID))
    BackColor(background_color)
    DrawingFont(FontID(font_ID))
    DrawText(0, 0, text$, text_color)
    StopDrawing()
    ProcedureReturn image_ID
  EndProcedure
  
  Procedure ScrollTextImageSimple_BF(image_ID, step_width=1)
    step_width*DesktopResolutionX()
    If step_width<1 : step_width=1 : EndIf
    Protected text_width=ImageWidth(image_ID)
    Protected text_height=ImageHeight(image_ID)
    If Not StartDrawing(ImageOutput(image_ID)) : ProcedureReturn 0 : EndIf
    Protected temp_image_1_ID=GrabDrawingImage(#PB_Any, 0, 0, step_width, text_height)
    If Not temp_image_1_ID : ProcedureReturn 0 : EndIf
    Protected temp_image_2_ID=GrabDrawingImage(#PB_Any, step_width, 0, text_width-step_width, text_height)
    If Not temp_image_2_ID : FreeImage(temp_image_1_ID) : ProcedureReturn 0 : EndIf
    DrawImage(ImageID(temp_image_1_ID), text_width-step_width, 0)
    DrawImage(ImageID(temp_image_2_ID), 0, 0)
    StopDrawing() 
    FreeImage(temp_image_1_ID) : FreeImage(temp_image_2_ID)
    ProcedureReturn image_ID
  EndProcedure
EndModule
UseModule ScrollingTextSimple_BF

; ###### Get the result ######

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
  
  Define font_ID=LoadFont(#PB_Any,"Tahoma", 24)
  Define text$="Hello World, this is scrolling text BF - "
  Define text_color=#Black
  Define background_color=#Green
  
  Define window_ID=OpenWindow(#PB_Any, 5 ,5 ,800 ,300 ,"Scrolling text" ,#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  SetWindowColor(window_ID, #Blue)
  
  Global image_ID=CreateTextImageSimple_BF(text$, font_ID, text_color, background_color) ; Init
  
  #CanvasOutput=#True ; Choose CanvasGadget for output or ButtonImagegadget
  
  If #CanvasOutput
    ; Output on a CanvasGadget
    Global gadget_ID=CanvasGadget(#PB_Any,
                                  WindowWidth(window_ID)/2-ImageWidth(image_ID)/2/DesktopResolutionX()/1.5,
                                  WindowHeight(window_ID)/3,
                                  ImageWidth(image_ID)/DesktopResolutionX()/1.5,
                                  ImageHeight(image_ID)/DesktopResolutionY(), #PB_Canvas_Border)
  Else 
    ; Output on a ButtonImageGadget
    gadget_ID=ButtonImageGadget(#PB_Any,
                                WindowWidth(window_ID)/2-ImageWidth(image_ID)/2/DesktopResolutionX()/1.5,
                                WindowHeight(window_ID)/3,
                                ImageWidth(image_ID)/DesktopResolutionX()/1.5,
                                ImageHeight(image_ID)/DesktopResolutionY(), 0) 
  EndIf
  
  Procedure DrawScrollingTextSimple()
    SetGadgetAttribute(gadget_ID, #PB_Button_Image, ImageID(image_ID))
    ScrollTextImageSimple_BF(image_ID, 1) ; 1 = Step width
    ProcedureReturn 1
  EndProcedure
  
  #BindEventMethod=#False ; Try what you want - WinOS is here bitchy
  
  If #BindEventMethod
    ; BindEvent method
    AddWindowTimer(window_ID, 1, 10) ; Speed
    BindEvent(#PB_Event_Timer, @DrawScrollingTextSimple())
    Repeat
      Define win_event=WaitWindowEvent()   
    Until win_event=#PB_Event_CloseWindow
  Else
    ; Timer method
    Define time
    Repeat
      Delay(1)
      If ElapsedMilliseconds()>time
        time=ElapsedMilliseconds()+10 ; Speed
        DrawScrollingTextSimple()
      EndIf
      Repeat
        Define win_event=WindowEvent()
        If win_event=#PB_Event_CloseWindow 
          End
        EndIf
      Until Not win_event 
    ForEver 
  EndIf
  
CompilerEndIf
Last edited by Saki on Sat Apr 10, 2021 12:43 am, edited 11 times in total.
地球上の平和
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by davido »

@Saki,
Another lovely example. Thank you for sharing. :D

Tested on MacBook Pro M1, Big Sur.
DE AA EB
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by BarryG »

Feedback: It's very jerky here on my PC. Not smooth scrolling at all. The text stops moving ever-so-slightly at what seems random times, and is due to using a timer event to control the speed, which isn't the right way to do it. From the manual: "timer events will only be generated when there are no other events to be processed". Even just moving the mouse over the window will generate events, therefore interrupting the timer and smoothness of the scrolling.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by Saki »

Code updated

Different Timer Methods added
Changing from Canvas to ButtonImageGadget as option added.

Davido and Barry, many thanks for testing.

@Barry
I don't know what OS you are using.
On Win10 the BindEvent works very well for me.
Linux and Mac usually don't cause any problems.
Win 7 and older Win versions have the nickname "flicker hell", I have not used this for a long time.
Win10 still has problems with judder, but far less than the old versions.

The low priority of the window timers usually only makes itself felt negatively if you use multiple window timers in parallel.

Then you go and use only one Windows timer.
This then sets a flag for each event.
Then you count up counters.
1 Event=10ms, 3 Event=30, 10 Event=100ms, as sample.

So you assign the single functions their events with a timer.
If you use more than one window timer it will not work under Windows, not even with Win 10.

Especially the horizontal animation under Windows is critical,
it will never be completely smooth, to time.... :(
You can fix it as far as possible, if you increase the timer delays, so that the animation does not become too fast.
You can fix it visually if you increase the delays, so that the animation is not too fast, or if you set the step greater than 1.
It's typical Windows, annoying and hard to get a grip on.

Try it and write then what is going on.
Last edited by Saki on Fri Apr 09, 2021 12:57 am, edited 1 time in total.
地球上の平和
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by BarryG »

Saki wrote:@Barry
I don't know what OS you are using.
On Win10 the BindEvent works very well for me.
Win10 still has problems with judder, but far less than the old versions.
I'm on Win 10 Pro and can easily see the judder that you mention. Using "#BindEventMethod=#True" makes it even worse.

As long as you're using window timers, it'll be jerky. Again from the manual: "Timers are therefore not suited for precise timing".
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by Saki »

I have made many hundreds of codes with animations, with and without Windows Timer.
The range of 20ms >30ms is not critical for an animation, it doesn't have to be 100%, you don't see it.
The jerking is a typical Windows problem.
It can be when you set a timer of 40ms everything runs clean and when you set 30ms it jerks so that it almost falls out of the screen,
no matter how you try to solve it.
地球上の平和
Bitblazer
Enthusiast
Enthusiast
Posts: 733
Joined: Mon Apr 10, 2017 6:17 pm
Location: Germany
Contact:

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by Bitblazer »

Saki wrote:I have made many hundreds of codes with animations, with and without Windows Timer.
On how many different hardware platforms did you verify this?
webpage - discord chat links -> purebasic GPT4All
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by Lunasole »

@BarryG
Can try some custom timer like this with simplest delay correction. May be improved further, but should be enough for such things.
There are also options to make window-based timers work great (of course on Windows too, the Linux is always more problematic), but need to search older code for this.
I like anyway variants like this (based on ElapsedMilliseconds), it's fine for many cases.

Code: Select all

EnableExplicit

Global Timer.q = ElapsedMilliseconds()
Global NextAction.q = Timer
Repeat
	Timer + ElapsedMilliseconds() - Timer
	If Timer >= NextAction
		; 16 is interval (ms)
		NextAction = Timer + 16 - (Timer - NextAction)
		Debug "Do action at " + Str(Timer)
	EndIf

	; some loop delay (like processing events)
	Delay(1)
ForEver
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by Saki »

@Barry, 99.9% of my programmes always run on Win, Linux and Mac.

@Lunasole, no, your part unfortunately has no positive effect here.

It's not so much a timer problem, the graphic output stops under Windows at a rhythm of a few seconds.
This depends on the event processing.

Whether these typical Windows micro-jerks are visible or not depends very much on the extent to which these
mostly small jerks run more or less randomly in sync with the delay used.
That's why it's always different, sometimes a lot, sometimes nothing.

What exactly is happening is probably not only a mystery to me, otherwise it would have been fixed long ago.

Normally I don't use the BindEvent method for this.
I only included it because the Delay(1) method is usually criticised.

The perfect solution is the one used in the Digi Clock.
The delay is adjusted automatically.
There has been a lot of unsuccessful about this, but it is possible.
Here with the scrolling text, however, in contrast to the clock, it is a part that does not belong in the module.
You then measure the speed of the animation and increase the delay until it begins to recede.
Look, the measurement is synchronised with the seconds, but this works also in the millisecond range.

Image
Last edited by Saki on Fri Apr 09, 2021 8:55 am, edited 4 times in total.
地球上の平和
devox
User
User
Posts: 32
Joined: Thu Apr 01, 2021 7:25 pm

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by devox »

Works fine here on Win10, thanks @Saki.
I'll try and use this in a project at some point.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Scrolling Text Simple - Module - DPI aware - All OS

Post by Saki »

Many thanks devox.

The next extended version will come.
地球上の平和
Post Reply