Page 1 of 1

Scrolling Text Simple - Module - DPI aware - All OS

Posted: Thu Apr 08, 2021 5:34 pm
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

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

Posted: Thu Apr 08, 2021 7:24 pm
by davido
@Saki,
Another lovely example. Thank you for sharing. :D

Tested on MacBook Pro M1, Big Sur.

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

Posted: Thu Apr 08, 2021 11:31 pm
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.

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

Posted: Fri Apr 09, 2021 12:38 am
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.

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

Posted: Fri Apr 09, 2021 12:52 am
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".

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

Posted: Fri Apr 09, 2021 1:09 am
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.

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

Posted: Fri Apr 09, 2021 2:14 am
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?

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

Posted: Fri Apr 09, 2021 5:07 am
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

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

Posted: Fri Apr 09, 2021 8:02 am
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

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

Posted: Fri Apr 09, 2021 8:38 am
by devox
Works fine here on Win10, thanks @Saki.
I'll try and use this in a project at some point.

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

Posted: Sat Apr 10, 2021 12:42 am
by Saki
Many thanks devox.

The next extended version will come.