Game Counter & Odometer & Digital clock - all OS - [Module]

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

Game Counter & Odometer & Digital clock - all OS - [Module]

Post by Saki »

Game Counter & Odometer & Digital clock- all OS - x64 x86 - DPI aware [Module]

Features :
Free scalable, any size adjustable with only one percent based parameter
Output on all channels available
Digital Clock - 24hr and 12hr AM/PM
Counter
Odometer
Countdown Counter
Countdown Odometer
Counters with System time synchronisation
Up to 15 chars supported
Gradient color supported
With and without tiling
Any fonts and fontsizes supported
Automatically fontsize
Transparence and Alpha Channel supported
Multi color with and without Alpha Channel supported
Background color adjustable
Frame Color adjustable
Tiling Color adjustable
Adjustable frame
Adjustable Odometer timer
Adjustable stepp timer
Adjustable clipping
And many more

The code can be extended or changed at will.
If you do, please post the result here in the thread.

Have fun with it.

Special feature : Gradient colored text also on MacOS - Full featured :wink:
Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Code: Select all

DeclareModule Odometer_OD
  EnableExplicit
  
  Declare InitOdometer_OD(percent_size_.d=120,         ; Adjust free the output size all over as percent
                          h_adjust_.d=1.00,            ; Fine adjust the frame left and right - Sample 50% resizing = 0.70
                          v_adjust_.q=0,               ; Fine adjust the vertical char position
                          frame_size_.d=3,             ; Frame size
                          delay_ms_.q=10,              ; Delay char moving speed - Milliseconds
                          delay_ms_step_.q=-2,         ; Delay step - Milliseconds - -1 Synchronized with the system time - -2 Clock
                          output_.q=0,                 ; Set a Start value
                          used_font_$="Arial",         ; Used font - If the specified start value is larger than the mask, the mask is expanded
                          number_of_chars_.q=8,        ; Number of chars - Up to 15 - If the start value is too large, the mask is automatic extended
                          frame_color_=#Red,           ; |$00000000,   ; Frame color      > For output with transparence set the alpha channel
                          char_color_=#Yellow,         ; |$FF000000, ; Character color  > When you set an alpha, the tool automatically switches to
                          back_color_=#Blue,           ; |$FF000000,  ; Background color > transparency mode and you must then refresh the background
                          remove_tiling_=#False,       ; Remove the char tiling
                          use_gradient_color_=#True,   ; Use gradient colors
                          clip_output_x_.d=0,          ; Clipping offset x   
                          clip_output_y_.d=0,          ; Clipping offset y
                          clip_output_xx_.d=0,         ; Clipping offset xx
                          clip_output_yy_.d=0,         ; Clipping offset yy
                          countdown_=#False)           ; Countdown Counter - Set a start value > 0 )
  
  ; Do not make delay_ms_step smaller than the required time for a number change, this breaks the alignment of the numbers
  
  Declare DrawOdometer_OD() ; Create the frames for output as image - Alpha Channel supported
                            ; You need to check if an image is available for output
  
  Declare SetUpOrDown_OD(SetUpOrDown_) ; Toggles between enumerate and countdown, changeable during runtime 1=Up - 2=Down
  
  Declare.q GetValueOdometer_OD() ; Get the actual counter & Odometer value
  
  Declare UseAMPM_OD(ampm_mode_=0) ; Use 12h AM/PM for a clock (preset) - Can be switched while the clock is running - Set after InitOdometer()
  
  Declare.s GetAMPM_OD() ; Get AM/PM state
  
  Declare StopOdometer_OD(value) ; Stop or start the animation - Set a value as stop-point - ignore = -1 - disable = -2 - stop directly = -3
                                 ; You must disable again
  
  Declare GetStopState_OD() ; Get the stop or start animation state
  
  Declare ActivateCountdown_OD(countdown_) ; Activate countdown mode
  
  Declare SetOutputValue_OD(count_) ; Set the output value
  
  Declare SetFrameColor_OD(frame_color_) ; Set the frame color
  
  Declare SetCharColor_OD(char_color_) ; Set the character color
  
  Declare SetBackColor_OD(back_color_) ; Set the background color
  
  Declare GetFrameWidth_OD() ; Get the frame width
  
  Declare GetFrameHeight_OD() ; Get the frame height
  
  Declare UseGradientColor_OD(UseGradientColor_=-1) ; Trigger gradient color -1=ignore - 0=disable - 1=enable
  
  ; Change the output size in percent - Set after InitOdometer_OD - From 60% > 300% (Preset=120%)
  ; This function auto adjust the animation delay
  Declare ChangeSizePercent_OD(PresetSizePercent_.d=0)
  
  Declare GetClockCycleLength_OD() ; Get the lengt from a animation cycle as ms - Timeout = -1
  
  Declare.q GetClockElapsedSeconds_OD() ; Get the elapsed seconds - clock based
  
  ; Auto adjust clock rolling speed (delay)
  ; This reduces the cores workload considerably - If a clock is running stand alone, a delay can be increased up to ~10
  Declare ClockAutoDelay_OD()
  
EndDeclareModule

Module Odometer_OD
  ; Game Counter & Odometer & Clock 24h and 12h AM/PM - By Saki - DPI aware - All OS - x64 x86
  
  Global QualityFactorMacOS.d=1.4 ; Quality factor for MacOS text with gradient color
                                  ; Bigger is better but progressively more computationally intensive
  
  Global clock_mode, stop, ChangeSizePercent.d, UseGradientColor=-1
  
  Global ampm$, noon$, ampm_mode
  Procedure.s GetTimeString() ; Set a valid time string here
    Protected seconds=Second(Date()), seconds$=RSet(Str(seconds), 2, "0")
    Protected hr_min$=RSet(Str(Hour(Date())), 2, "0")+RSet(Str(Minute(Date())), 2, "0")
    If ampm_mode And clock_mode=2
      Protected time=Val(hr_min$)
      Select time
        Case 0 To 99
          ampm$="AM" : time+1200 : noon$="Midn"
        Case 100 To 1159
          ampm$="AM" : noon$=#Null$
        Case 1200 To 1259
          ampm$="PM" : noon$="Noon"
        Case 1300 To 2359
          ampm$="PM" : time-1200 : noon$=#Null$    
      EndSelect 
      ProcedureReturn RSet(Str(time), 4, "0")+seconds$
    Else
      noon$=#Null$
      ProcedureReturn hr_min$+seconds$
    EndIf
  EndProcedure
  
  Procedure InitOdometer_OD(percent_size_.d=120,       ; Adjust free the output size all over as percent
                            h_adjust_.d=1.00,          ; Fine adjust the frame left and right - Sample 50% resizing = 0.70
                            v_adjust_.q=0,             ; Fine adjust the vertical char position
                            frame_size_.d=3,           ; Frame size
                            delay_ms_.q=10,            ; Delay char moving speed - Milliseconds
                            delay_ms_step_.q=-2,       ; Delay step - Milliseconds - -1 Synchronized with the system time - -2 Clock
                            output_.q=0,               ; Set a Start value
                            used_font_$="Arial",       ; Used font - If the specified start value is larger than the mask, the mask is expanded
                            number_of_chars_.q=8,      ; Number of chars - Up to 15 - If the start value is too large, the mask is automatic extended
                            frame_color_=#Red,         ; |$00000000,   ; Frame color      > For output with transparence set the alpha channel
                            char_color_=#Yellow,       ; |$FF000000, ; Character color  > When you set an alpha, the tool automatically switches to
                            back_color_=#Blue,         ; |$FF000000,  ; Background color > transparency mode and you must then refresh the background
                            remove_tiling_=#False,     ; Remove the char tiling
                            use_gradient_color_=#True, ; Use gradient colors
                            clip_output_x_.d=0,        ; Clipping offset x   
                            clip_output_y_.d=0,        ; Clipping offset y
                            clip_output_xx_.d=0,       ; Clipping offset xx
                            clip_output_yy_.d=0,       ; Clipping offset yy
                            countdown_=#False)         ; Countdown Counter - Set a start value > 0 )
    
    If UseGradientColor=1 : use_gradient_color_=1 : ElseIf Not UseGradientColor : use_gradient_color_=0 : EndIf
    
    If Not ChangeSizePercent.d
      UseAMPM_OD(1) ; Init AMPM clock mode
      
      If delay_ms_step_=-1 : clock_mode=1 : ElseIf delay_ms_step_=-2 : number_of_chars_=6 : clock_mode=2 : EndIf
      
      Global percent_size.d=percent_size_.d
      Global h_adjust.d=h_adjust_.d
      Global v_adjust.q=v_adjust_.q
      Global frame_size.d=frame_size_.d
      Global delay_ms.q=delay_ms_.q
      Global delay_ms_step.q=delay_ms_step_.q
      Global output.q=output_.q
      Global used_font$=used_font_$
      Global number_of_chars.q=number_of_chars_.q
      Global frame_color=frame_color_
      Global char_color=char_color_
      Global back_color=back_color_
      Global remove_tiling=remove_tiling_
      Global use_gradient_color=use_gradient_color_
      Global clip_output_x.d=clip_output_x_.d
      Global clip_output_y.d=clip_output_y_.d
      Global clip_output_xx.d=clip_output_xx_.d
      Global clip_output_yy.d=clip_output_yy_.d
      Global countdown=countdown_
      Global DR.d=DesktopResolutionX()
      
    Else
      Select ChangeSizePercent
        Case 60  : delay_ms=delay_ms_*1.5
        Case 70  : delay_ms=delay_ms_*1.4
        Case 80  : delay_ms=delay_ms_*1.3
        Case 90  : delay_ms=delay_ms_*1.2
        Case 100 : delay_ms=delay_ms_*1.1
        Case 110 : delay_ms=delay_ms_*1.0
        Case 120 : delay_ms=delay_ms_*0.9
        Case 130 : delay_ms=delay_ms_*0.7
        Case 140 : delay_ms=delay_ms_*0.6
        Case 150 : delay_ms=delay_ms_*0.5
        Case 160 : delay_ms=delay_ms_*0.3
      EndSelect
      frame_size=frame_size_.d/120*ChangeSizePercent.d
      If frame_size_>0 And frame_size_<1 : frame_size=1 : EndIf
    EndIf
    
    CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
      If use_gradient_color : percent_size*QualityFactorMacOS : EndIf
    CompilerEndIf
    
    Static static_font_ID
    If IsFont(static_font_ID) : FreeFont(static_font_ID) : EndIf
    CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
      Global font_ID=LoadFont(#PB_Any, used_font$, 33/100*percent_size)
    CompilerElse
      Global font_ID=LoadFont(#PB_Any, used_font$, 25/100*percent_size)
    CompilerEndIf
    If Not IsFont(font_ID) : ProcedureReturn 0 : EndIf
    static_font_ID=font_ID
    
    Static static_font_1_ID
    If IsFont(static_font_1_ID) : FreeFont(static_font_1_ID) : EndIf
    CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
      Global font_1_ID=LoadFont(#PB_Any, used_font$, 12/100*percent_size)
    CompilerElse
      Global font_1_ID=LoadFont(#PB_Any, used_font$, 9/100*percent_size)
    CompilerEndIf
    If Not IsFont(font_ID) : FreeFont(font_ID) : ProcedureReturn 0 : EndIf
    static_font_1_ID=font_1_ID
    
    If clock_mode=2 : output=Val(GetTimeString()) : EndIf     
    If Len(Str(output))>15 : output=Val(LSet("9", 15, "9")) : EndIf
    If Len(Str(output))>number_of_chars : number_of_chars=Len(Str(output)) : EndIf
    If countdown And Not output : output=Val(LSet("9", number_of_chars, "9")) : EndIf
    
    Global v_chr_space.d=34/100*percent_size, tile_width.d=20/100*percent_size
    Global mid_preset$, v_offset.d=37/100*percent_size, image_ID, ampm_offset, force
    Global count.d=output, stop_animation, SetUpOrDown, output_width, output_height
    Global clock_cycle_measure_0, clock_cycle_measure_1, GetClockCycleLength, GetClockElapsedSeconds.q=-1
    Global clock_seconds_measure_0, clock_seconds_measure_1, clock_seconds_measure_2
    Global max_value.d=Val(LSet("9", number_of_chars, "9"))
    
    If Alpha(frame_color|char_color|back_color) : Global transparency=1 : EndIf
    If number_of_chars<2 : number_of_chars=1 : EndIf
    
    Global i, ii, iii, i1, i2.d=2*h_adjust.d*DR, i3.d, i4, change, clock_time, clock_time$
    Global time.q, time_1.q, preset$, output$, preset.q, output_1.q, count_1, init=1, clock_offset, first_init=1
    output+Val("1"+LSet("0", number_of_chars,"0")) : preset=output
    If countdown : output_1=output-1 : Else : output_1=output+1 : EndIf
    change=Len(Str(output)) : frame_size=(frame_size-1)*DR
    time_1=ElapsedMilliseconds()+delay_ms_step-delay_ms
    clip_output_x/100*percent_size*DR : clip_output_y/100*percent_size*DR
    clip_output_xx/100*percent_size*DR : clip_output_yy/100*percent_size*DR
    If clock_mode=2 : clock_offset=36/100*percent_size : If remove_tiling : clock_offset/2 : EndIf : EndIf
    If ampm_mode And clock_mode=2 : ampm_offset=40/100*percent_size : Else : ampm_offset=0 : EndIf
    output_width=((tile_width*number_of_chars)+2+clock_offset)*DR+ampm_offset*DR                       
    output_height=v_offset*DR
    
    ProcedureReturn 1
  EndProcedure ; InitOdometer_OD
  
  Procedure Callback_CreateImage(x, y, source_color, destination_color)
    If destination_color&$FFFFFF<>char_color&$FFFFFF
      ProcedureReturn destination_color
    EndIf
    ProcedureReturn source_color
  EndProcedure
  
  Procedure CreateGradientImage(image_ID)
    If Not IsImage(image_ID)
      ProcedureReturn 0
    EndIf
    
    If clip_output_x.d Or clip_output_y.d Or clip_output_xx.d Or clip_output_yy.d : Protected use_clipping=1 : EndIf
    
    If UseGradientColor=1 Or UseGradientColor=-1
      If use_gradient_color
        Protected temporary_image_ID=CreateImage(#PB_Any, ImageWidth(image_ID), ImageHeight(image_ID), 24, char_color)
        If Not temporary_image_ID
          ProcedureReturn 0
        EndIf
        
        If StartDrawing(ImageOutput(temporary_image_ID))
          DrawingMode(#PB_2DDrawing_Gradient)
          FrontColor(frame_color)
          BackColor(frame_color)
          GradientColor(0.5, char_color)
          LinearGradient(0,ImageHeight(image_ID)+ImageHeight(image_ID)/8, 0, -ImageHeight(image_ID)/8)
          Box(0, 0, ImageWidth(image_ID), ImageHeight(image_ID))
          StopDrawing()
        Else
          FreeImage(temporary_image_ID)
          ProcedureReturn 0
        EndIf
      EndIf
      
      If StartDrawing(ImageOutput(image_ID))
        DrawingMode(#PB_2DDrawing_CustomFilter)
        CustomFilterCallback(@Callback_CreateImage())
        DrawImage(ImageID(temporary_image_ID), 0, 0)
        StopDrawing()
        FreeImage(temporary_image_ID)
      EndIf
    EndIf
    
    ResizeImage(image_ID, ImageWidth(image_ID)/QualityFactorMacOS, ImageHeight(image_ID)/QualityFactorMacOS)
    If Not use_clipping : ProcedureReturn image_ID : EndIf
    
    Protected clip_output_x_.d=clip_output_x.d
    Protected clip_output_y_.d=clip_output_y.d
    Protected clip_output_xx_.d=ImageWidth(image_ID)+clip_output_xx.d
    Protected clip_output_yy_.d=ImageHeight(image_ID)+clip_output_yy.d
    If clip_output_x_.d=>0 And clip_output_y_.d=>0 And clip_output_xx_.d>0 And clip_output_yy_.d>0
      Protected grabed_image_ID=GrabImage(image_ID, #PB_Any,
                                          clip_output_x_.d,
                                          clip_output_y_.d,
                                          clip_output_xx_.d,
                                          clip_output_yy_.d)
      If Not grabed_image_ID : ProcedureReturn 0 : EndIf
      FreeImage(image_ID)
      ProcedureReturn grabed_image_ID
    EndIf
  EndProcedure
  
  Procedure DrawOdometer_OD()
    Static clock_event, old_clock_time$
    If force Or (ElapsedMilliseconds()=>time+delay_ms And Not (stop And i3=>v_chr_space*DR))
      If Not first_init : InitOdometer_OD() : first_init=1 : EndIf
      If SetUpOrDown=1 : countdown=0 : ElseIf SetUpOrDown=2 : countdown=1 : EndIf
      If stop_animation And Not i3-DR : Goto finish : EndIf
      i1=i2
      If clock_mode
        If clock_mode=2 : clock_offset=6/100*percent_size
          If remove_tiling : clock_offset/2 : EndIf
          i1+(clock_offset*DR)
        EndIf
        clock_time$=GetTimeString() : clock_time=Val(clock_time$)
        If old_clock_time$<>clock_time$ : GetClockElapsedSeconds.q+1 : clock_event=1 : old_clock_time$=clock_time$ : EndIf
      EndIf
      
      If clock_mode=2
        If ampm_mode : clock_offset=34/100*percent_size : Else : clock_offset=37/100*percent_size : EndIf
        If remove_tiling : clock_offset/2 : EndIf
      EndIf
      
      If ampm_mode And clock_mode=2 : ampm_offset=40/100*percent_size : Else : ampm_offset=0 : EndIf
      
      If Alpha(frame_color|char_color|back_color) : transparency=1 : Else : transparency=0 : EndIf
      
      output_width=((tile_width*number_of_chars)+2+clock_offset)*DR+ampm_offset*DR                       
      output_height=v_offset*DR
      
      If transparency
        image_ID=CreateImage(#PB_Any, output_width, output_height, 32, #PB_Image_Transparent)
      Else
        image_ID=CreateImage(#PB_Any, output_width, output_height, 24, back_color)
      EndIf
      
      If Not image_ID : ProcedureReturn 0 : EndIf
      
      CompilerIf #PB_Compiler_OS<>#PB_OS_MacOS
        StartDrawing(ImageOutput(image_ID))
        DrawingFont(FontID(font_ID))
        ClipOutput(clip_output_x,
                   clip_output_y,
                   (ImageWidth(image_ID)+clip_output_xx*DR)*DR,
                   (ImageHeight(image_ID)+clip_output_yy*DR)*DR)
      CompilerEndIf
      
      For i4=2 To change
        CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
          StartDrawing(ImageOutput(image_ID))
          DrawingFont(FontID(font_ID))
          ; ClipOutput(clip_output_x, ; Deactivated PB573 Bug
          ;            clip_output_y,
          ;            (ImageWidth(image_ID)+clip_output_xx*DR)*DR,
          ;            (ImageHeight(image_ID)+clip_output_yy*DR)*DR)
        CompilerEndIf
        
        mid_preset$=Mid(preset$, i4, 1)
        
        CompilerIf #PB_Compiler_OS<>#PB_OS_MacOS
          If use_gradient_color
            If transparency
              DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_Transparent|#PB_2DDrawing_AlphaBlend)
            Else
              DrawingMode(#PB_2DDrawing_Gradient)
            EndIf
            If use_gradient_color
              FrontColor(frame_color)
              BackColor(frame_color)
              GradientColor(0.5, char_color)
              LinearGradient(0,ImageHeight(image_ID)+ImageHeight(image_ID)/8, 0, -ImageHeight(image_ID)/8)
            EndIf
          Else
            If transparency : DrawingMode(#PB_2DDrawing_Transparent|#PB_2DDrawing_AlphaBlend) : EndIf
          EndIf
        CompilerElse
          If transparency : DrawingMode(#PB_2DDrawing_Transparent|#PB_2DDrawing_AlphaBlend) : EndIf
        CompilerEndIf
        
        If clock_mode=2 And Not stop_animation
          preset$=RSet(GetTimeString(), 6, "0") : count_1=Val(preset$) : preset$="1"+preset$ : output_1=Val(preset$)
        EndIf
        preset$=Str(output_1) : output$=Str(preset)
        
        If mid_preset$<>Mid(output$, i4, 1)
          DrawText(i1, (v_chr_space+v_adjust)*DR-i3, Mid(Str(output_1), i4, 1), char_color, back_color)
          DrawText(i1, -i3+v_adjust*DR, Mid(output$, i4, 1), char_color, back_color)
        Else
          DrawText(i1, v_adjust*DR, mid_preset$, char_color, back_color)
        EndIf   
        
        If ampm_mode And clock_mode=2
          DrawingFont(FontID(font_1_ID))
          DrawText((ImageWidth(image_ID)-ampm_offset*DR+8*DR/100*percent_size),
                   5/100*percent_size*DR, ampm$, char_color, back_color)
          DrawText((ImageWidth(image_ID)-ampm_offset*DR+3*DR/100*percent_size),
                   18/100*percent_size*DR, noon$, char_color, back_color)
          DrawingFont(FontID(font_ID))
        EndIf
        
        If transparency
          DrawingMode(#PB_2DDrawing_Outlined|#PB_2DDrawing_AlphaBlend)
        Else
          DrawingMode(#PB_2DDrawing_Outlined)
        EndIf
        
        If Not remove_tiling
          If clock_mode=2
            If transparency
              CompilerIf #PB_Compiler_OS<>#PB_OS_MacOS
                DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_AlphaBlend)
              CompilerElse
                DrawingMode(#PB_2DDrawing_AlphaBlend)
              CompilerEndIf
            Else
              CompilerIf #PB_Compiler_OS<>#PB_OS_MacOS
                DrawingMode(#PB_2DDrawing_Gradient)
              CompilerElse
                DrawingMode(#PB_2DDrawing_Default)
              CompilerEndIf
            EndIf
            ii=DR/2
            For i=1 To number_of_chars-2 Step 2
              ii+tile_width*2*DR : iii=0
              Repeat
                If i=3 : clock_offset=24/100*percent_size : Else : clock_offset=12/100*percent_size : EndIf
                If remove_tiling : clock_offset/2 : EndIf
                FrontColor(char_color)
                Circle(ii+iii+clock_offset*DR, ImageHeight(image_ID)/2, 2/100*percent_size*DR, char_color)
                iii+1           
              Until iii>1*DR
            Next
          Else
            ii=DR/2
            For i=1 To number_of_chars
              ii+tile_width*DR : iii=0
              Repeat
                Box(0, 0, ii+iii, ImageHeight(image_ID), frame_color) : iii+1
              Until iii>1*DR
            Next
          EndIf
        EndIf
        
        If transparency
          DrawingMode(#PB_2DDrawing_Outlined|#PB_2DDrawing_AlphaBlend)
        Else
          DrawingMode(#PB_2DDrawing_Outlined)
        EndIf
        
        For i=0 To frame_size : Box(i, i, ImageWidth(image_ID)-i*2, ImageHeight(image_ID)-i*2, frame_color) : Next
        
        If clock_mode=2
          clock_offset=12/100*percent_size
          If remove_tiling : clock_offset/2 : EndIf
          If i4=3 Or i4=5 : i1+(tile_width+clock_offset)*DR : Else : i1+tile_width*DR : EndIf
        Else
          i1+tile_width*DR
        EndIf
        
        CompilerIf #PB_Compiler_OS=#PB_OS_MacOS : StopDrawing() : CompilerEndIf
      Next
      
      CompilerIf #PB_Compiler_OS<>#PB_OS_MacOS : StopDrawing() : CompilerEndIf
      
      If Not countdown ; Up
        
        If init
          If ElapsedMilliseconds()=>time_1-delay_ms
            time_1=ElapsedMilliseconds()+delay_ms_step : count+1
            If count>max_value : count=max_value : stop=2 : Goto finish : EndIf
            init=0 : clock_event=0
          EndIf
        Else
          If clock_mode
            If clock_event 
              clock_cycle_measure_0=ElapsedMilliseconds()
              If clock_seconds_measure_0<2
                GetClockCycleLength=1000-clock_cycle_measure_1
              Else
                GetClockCycleLength=-1
              EndIf
              i3+1*DR
            Else
              clock_cycle_measure_1=ElapsedMilliseconds()-clock_cycle_measure_0
            EndIf
          Else
            i3+1*DR
          EndIf
          If i3>v_chr_space*DR
            If count=max_value : If clock_mode : count+1 : EndIf : stop=2 : Goto finish :  EndIf
            clock_event=0 : i3=0 : preset=output_1
            If ElapsedMilliseconds()=>time_1-delay_ms
              clock_seconds_measure_0=GetClockElapsedSeconds-clock_seconds_measure_1
              clock_seconds_measure_1=GetClockElapsedSeconds
              clock_seconds_measure_2+1
              time_1=ElapsedMilliseconds()+delay_ms_step
              If Not stop_animation Or clock_mode
                count+1 : output_1+1
              EndIf
            EndIf
          EndIf
          time=ElapsedMilliseconds()
        EndIf
        
      Else ; Down
        
        If init
          If ElapsedMilliseconds()=>time_1-delay_ms
            time_1=ElapsedMilliseconds()+delay_ms_step : count-1
            If Not clock_mode : If count<1 : count=0 : stop=1 : EndIf : EndIf : init=0 : clock_event=0
          EndIf
        Else
          If clock_mode : If clock_event : If count<0 : stop=1 : Else : i3+1*DR : EndIf : EndIf
          EndIf
          If i3=>v_chr_space*DR
            clock_event=0 : i3=0 : preset=output_1
            If ElapsedMilliseconds()=>time_1-delay_ms
              time_1=ElapsedMilliseconds()+delay_ms_step
              If Not stop_animation : count-1 : If delay_ms_step<0 : output_1-1 : EndIf : EndIf
              If Not clock_mode : If count<0 : count=0 : stop=1 : Goto finish : EndIf : EndIf 
              If delay_ms_step>-1 : output_1-1 : EndIf
            EndIf
          EndIf
          If Not clock_mode : i3+1*DR : EndIf
          time=ElapsedMilliseconds()
        EndIf
      EndIf
      
    EndIf
    
    finish:
    CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
      image_ID=CreateGradientImage(image_ID)
    CompilerEndIf
    ProcedureReturn image_ID
  EndProcedure ; DrawOdometer_OD
  
  Procedure SetUpOrDown_OD(SetUpOrDown_)
    SetUpOrDown=SetUpOrDown_
    ProcedureReturn SetUpOrDown
  EndProcedure
  
  Procedure.q GetValueOdometer_OD()
    If clock_mode=1
      If countdown : ProcedureReturn count+1 : EndIf
      ProcedureReturn count-1
    ElseIf clock_mode=2
      ProcedureReturn count_1
    Else
      If countdown : ProcedureReturn count+stop_animation : EndIf
      ProcedureReturn count
    EndIf
  EndProcedure
  
  Procedure UseAMPM_OD(ampm_mode_=0)
    ampm_mode=ampm_mode_
    ProcedureReturn ampm_mode
  EndProcedure
  
  Procedure.s GetAMPM_OD()
    ProcedureReturn ampm$+" "+RTrim(noon$)
  EndProcedure
  
  Procedure StopOdometer(stop_animation_=#False)
    stop_animation=stop_animation_
    ProcedureReturn stop_animation
  EndProcedure
  
  Procedure StopOdometer_OD(value)
    If value=-2 : StopOdometer(0) : ProcedureReturn value : EndIf
    If value=-3 : StopOdometer(1) : ProcedureReturn value : EndIf
    If value>-1 : If GetValueOdometer_OD()=value : StopOdometer(1) : EndIf : EndIf
    ProcedureReturn value
  EndProcedure
  
  Procedure GetStopState_OD()
    ProcedureReturn stop_animation
  EndProcedure
  
  Procedure ActivateCountdown_OD(countdown_)
    countdown=countdown_
    ProcedureReturn countdown
  EndProcedure
  
  Procedure SetOutputValue_OD(output_)
    If output_<0 : output_=0 : EndIf
    If output_>max_value-countdown*2 : output_=max_value-2+countdown*4 : EndIf
    output=output_-1 : stop=0
    If clock_mode=2 : output=Val(GetTimeString()) : EndIf     
    If Len(Str(output))>15 : output=Val(LSet("9", 15, "9")) : EndIf
    If Len(Str(output))>number_of_chars : number_of_chars=Len(Str(output))-countdown : EndIf
    If countdown And Not output : output=Val(LSet("9", number_of_chars, "9")) : EndIf
    If countdown : count.d=output-1 : Else : count.d=output+1 : EndIf
    max_value.d=Val(LSet("9", number_of_chars, "9"))
    If number_of_chars<2 : number_of_chars=1 : EndIf
    output+Val("1"+LSet("0", number_of_chars,"0")) : preset=output
    If countdown : output_1=output-1 : Else : output_1=output+1 : EndIf
    count_1-1 : i3=v_chr_space*DR : time=ElapsedMilliseconds()-delay_ms
    ProcedureReturn output
  EndProcedure
  
  Procedure SetFrameColor_OD(frame_color_)
    frame_color=frame_color_
    ProcedureReturn frame_color
  EndProcedure
  
  Procedure SetCharColor_OD(char_color_)
    char_color=char_color_
    ProcedureReturn char_color
  EndProcedure
  
  Procedure SetBackColor_OD(back_color_)
    back_color=back_color_
    ProcedureReturn back_color
  EndProcedure
  
  Procedure GetFrameWidth_OD()
    force=1
    Protected timeout.q=ElapsedMilliseconds()+20
    Repeat
      Define temp_image_ID=DrawOdometer_OD()
    Until IsImage(temp_image_ID) Or ElapsedMilliseconds()>timeout
    force=0
    If IsImage(temp_image_ID)
      Define frame_width=ImageWidth(temp_image_ID)
      FreeImage(temp_image_ID)
      ProcedureReturn frame_width
    Else
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure GetFrameHeight_OD()
    force=1
    Protected timeout.q=ElapsedMilliseconds()+20
    Repeat
      Define temp_image_ID=DrawOdometer_OD() 
    Until IsImage(temp_image_ID) Or ElapsedMilliseconds()>timeout
    force=0
    If IsImage(temp_image_ID)
      Define frame_height=ImageHeight(temp_image_ID)
      FreeImage(temp_image_ID)
      ProcedureReturn frame_height
    Else
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure ChangeSizePercent_OD(ChangeSizePercent_.d=0)
    If ChangeSizePercent_.d<60 : ChangeSizePercent_.d=60 : EndIf
    If ChangeSizePercent_.d>160 : ChangeSizePercent_.d=160 : EndIf
    CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
      ChangeSizePercent_.d*1.4
    CompilerEndIf 
    ChangeSizePercent.d=ChangeSizePercent_.d
    percent_size.d=ChangeSizePercent_
    InitOdometer_OD()
    ChangeSizePercent=0
    ProcedureReturn 1
  EndProcedure
  
  Procedure UseGradientColor_OD(UseGradientColor_=-1)
    UseGradientColor=UseGradientColor_
    CompilerIf #PB_Compiler_OS<>#PB_OS_MacOS
      use_gradient_color=UseGradientColor_
    CompilerEndIf
    ProcedureReturn UseGradientColor
  EndProcedure
  
  Procedure GetClockCycleLength_OD()
    ProcedureReturn GetClockCycleLength
  EndProcedure
  
  Procedure.q GetClockElapsedSeconds_OD()
    If GetClockElapsedSeconds.q<0
      ProcedureReturn 0
    EndIf
    ProcedureReturn GetClockElapsedSeconds.q
  EndProcedure
  
  Procedure ClockAutoDelay_OD()
    Static seconds_changed, delay
    Protected GetClockCycleLength_=GetClockCycleLength_OD()
    Protected GetClockElapsedSeconds_=GetClockElapsedSeconds_OD()
    If seconds_changed<>GetClockElapsedSeconds_
      seconds_changed=GetClockElapsedSeconds_
      If GetClockCycleLength_>600 Or GetClockCycleLength_<0  ; histeresis
        delay-1
      ElseIf GetClockCycleLength_<600 And GetClockCycleLength_>-1
        delay+1
      EndIf
    EndIf
    If delay<0 : delay=0 : EndIf
    Delay(delay)
    ProcedureReturn delay
  EndProcedure
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  UseModule Odometer_OD
  
  ; ########################## Use the module #############################
  
  ; Make the output DPI aware under WinOS not too big, on 4K it can get tight fast.
  ; 120% on DPI aware should be fine even on slower machines.
  ; But you can also resize the output image as you like, up to about 200% DPI aware still gives a good quality.
  
  EnableExplicit
  
  Define window_ID=OpenWindow(#PB_Any, 0, 0, 500, 300, "Game Counter & Odometer & Clock", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  AddWindowTimer(window_ID, 1, 100)
  Define canvas_ID=CanvasGadget(#PB_Any, 0, 0, WindowWidth(window_ID), WindowHeight(window_ID), #PB_Canvas_Container)
  
  Define button_1_ID=ButtonGadget(#PB_Any, 150, WindowHeight(window_ID)-160, 200, 30, "Stop the animation")
  Define button_2_ID=ButtonGadget(#PB_Any, 150, WindowHeight(window_ID)-110, 200, 30, "Switch to 24 hours mode")
  Define button_3_ID=ButtonGadget(#PB_Any, 150, WindowHeight(window_ID)-60, 200, 30, "Switch the colors")
  
  CloseGadgetList()
  
  Define percent_size.d=120       ; Adjust free the output size all over as percent
  Define h_adjust.d=1.00          ; Fine adjust the frame left and right - Sample 50% resizing = 0.70
  Define v_adjust.q=0             ; Fine adjust the vertical char position
  Define frame_size.q=3           ; Frame size
  Define delay_ms.q=6             ; Delay char moving speed - Milliseconds
  Define delay_ms_step.q=-2       ; Delay step - Milliseconds - -1 Synchronized with the system time - -2 Clock
  Define output.q=10              ; Set a Start value
  Define used_font$="Arial"       ; Used font - If the specified start value is larger than the mask, the mask is expanded
  Define number_of_chars.q=8      ; Number of chars - Up to 15 - If the start value is too large, the mask is automatic extended
  Define frame_color=#Red         ; |$FF000000   ; Frame color      > For output with transparence set the alpha channel
  Define char_color=#Yellow       ; |$FF000000 ; Character color  > When you set an alpha, the tool automatically switches to
  Define back_color=#Blue         ; |$FF000000   ; Background color > transparency mode and you must then refresh the background
  Define remove_tiling=#False     ; Remove the char tiling
  Define use_gradient_color=#True ; Use gradient colors
  Define clip_output_x.d=0        ; Clipping offset x   
  Define clip_output_y.d=0        ; Clipping offset y
  Define clip_output_xx.d=0       ; Clipping offset xx
  Define clip_output_yy.d=0       ; Clipping offset yy
  Define countdown=#False         ; Countdown Counter - Set a start value > 0
  
  ; Settings for a other clock 1
  ; Define frame_size.q=3               ; Frame size
  ; Define frame_color=#Red|$FF000000   ; Frame color      > For output with transparence set the alpha channel
  ; Define char_color=#Yellow|$FF000000 ; Character color  > When you set an alpha, the tool automatically switches to
  ; Define back_color=#Blue|$FF000000   ; Background color > transparency mode and you must then refresh the background
  ; Define remove_tiling=#False         ; Remove the char tiling
  
  ; Settings for a other clock 2
  ; Define frame_color=#Blue            ; Frame color > For output with transparence set the alpha channel
  ; Define remove_tiling=#True          ; Remove the char tiling
  ; Define frame_size.q=3               ; Frame size
  
  ; Settings for a Counter with System clock synchronization
  ; Define delay_ms_step.q=-1           ; Delay step - Milliseconds - -1 Synchronized with the system time
  ; Define frame_color=#Red|$00000000   ; Frame color > For output with transparence set the alpha channel
  
  ; Settings for a Odometer
  ; Define delay_ms.q=15                ; Delay char moving speed - Milliseconds
  ; Define delay_ms_step.q=0            ; Delay step - Milliseconds - -1 Synchronized with the system time
  ; Define frame_color=#Red|$00000000   ; Frame color > For output with transparence set the alpha channel
  
  ; For setup you can also call InitOdometer_OD without any parameters at all - You can even omit it
  InitOdometer_OD(percent_size.d,     ; Adjust free the output size all over as percent
                  h_adjust.d,         ; Fine adjust the frame left and right - Sample 50% resizing = 0.70
                  v_adjust.q,         ; Fine adjust the vertical char position
                  frame_size.q,       ; Frame size
                  delay_ms.q,         ; Delay char moving speed - Milliseconds
                  delay_ms_step.q,    ; Delay step - Milliseconds - -1 Synchronized with the system time - -2 Clock
                  output.q,           ; Set a Start value
                  used_font$,         ; Used font - If the specified start value is larger than the mask, the mask is expanded
                  number_of_chars.q,  ; Number of chars - Up to 15 - If the start value is too large, the mask is automatic extended
                  frame_color,        ; Frame color      > For output with transparence set the alpha channel
                  char_color,         ; Character color  > When you set an alpha, the tool automatically switches to
                  back_color,         ; Background color > transparency mode and you must then refresh the background
                  remove_tiling,      ; Remove the char tiling
                  use_gradient_color, ; Use gradient colors
                  clip_output_x.d,    ; Clipping offset x   
                  clip_output_y.d,    ; Clipping offset y
                  clip_output_xx.d,   ; Clipping offset xx
                  clip_output_yy.d,   ; Clipping offset yy
                  countdown)          ; Countdown Counter - Set a start value > 0
  
  ; UseAMPM_OD(1) ; Use 12h AM/PM for a clock (preset) - Can be switched while the clock is running - Set after InitOdometer()
  
  Define DR.d=DesktopResolutionX()
  
  ; ==== This little part works so not on Linux - Linux can not read the #PB_Compiler_Home path ====
  UseJPEGImageDecoder()
  Define image_0_ID=LoadImage(#PB_Any, #PB_Compiler_Home+"Examples/3D/Data/Textures/grass.jpg")
  If Not image_0_ID
    image_0_ID=CreateImage(#PB_Any, WindowWidth(window_ID)*DR, WindowHeight(window_ID)*DR, 24, $505050)
  EndIf
  ResizeImage(image_0_ID, WindowWidth(window_ID)*DR, WindowHeight(window_ID)*DR)
  StartDrawing(CanvasOutput(canvas_ID))
  DrawImage(ImageID(image_0_ID), 0, 0)
  StopDrawing()
  ; =========================================================================================
  
  Define button_1_state, button_2_state, button_3_state
  Repeat ; ### Main loop ### 
    
    ; Auto adjust clock rolling speed (delay)
    ; This reduces the cores workload considerably - If a clock is running stand alone, a delay can be increased up to ~10
    Define delay=ClockAutoDelay_OD()
    
    Repeat ; Get ever all events 
      Define win_event=WindowEvent() ; Add here your events - Just like they always do
      If win_event=#PB_Event_Timer And EventTimer()=1
        If GetStopState_OD() : DisableGadget(button_2_ID, 1) : Else : DisableGadget(button_2_ID, 0) : EndIf
        If GetStopState_OD() : DisableGadget(button_3_ID, 1) : Else : DisableGadget(button_3_ID, 0) : EndIf
      EndIf
      If win_event=#PB_Event_Gadget
        Select EventGadget()
          Case button_1_ID
            button_1_state=GetGadgetData(button_1_ID)
            If button_1_state
              SetGadgetText(button_1_ID, "Stop the animation")
              StopOdometer_OD(-2)
            Else
              SetGadgetText(button_1_ID, "Start the animation")
              StopOdometer_OD(-3)
            EndIf
            SetGadgetData(button_1_ID, 1-button_1_state)
          Case button_2_ID
            If Not GetStopState_OD()
              button_2_state=GetGadgetData(button_2_ID)
              If button_2_state
                SetGadgetText(button_2_ID, "Switch to 24 hours mode")
              Else
                SetGadgetText(button_2_ID, "Switch to 12 hours mode")
              EndIf
              UseAMPM_OD(GetGadgetData(button_2_ID))
              SetGadgetData(button_2_ID, 1-button_2_state)
            EndIf
          Case button_3_ID
            If Not GetStopState_OD()
              button_3_state=GetGadgetData(button_3_ID)
              If button_3_state
                SetFrameColor_OD(frame_color&$FFFFFF)
                SetCharColor_OD(char_color&$FFFFFF)
              Else
                SetFrameColor_OD(#Green|$FF000000)
                SetCharColor_OD(char_color|$FF000000)
              EndIf
              SetGadgetData(button_3_ID, 1-button_3_state)
            EndIf
        EndSelect
      EndIf
      If win_event=#PB_Event_CloseWindow : End : EndIf
    Until Not win_event
    
    ; ############# Get the result ##############
    Define image_ID=DrawOdometer_OD() ; Create the frames for output as image - Alpha Channel supported
                                      ; You need ever to check if an image is available for output
    
    StartDrawing(CanvasOutput(canvas_ID))
    If IsImage(image_ID) ; You need ever to check if an image is available for output
      If image_0_ID      ; Firstly output the background image
        DrawImage(ImageID(image_0_ID), 0, 0)
      EndIf
      ; ResizeImage(image_ID, ImageWidth(image_ID)*2, ImageHeight(image_ID)*2) ; Double the image (frame) size for output
      DrawAlphaImage(ImageID(image_ID), ; Output the image (frame) - With visible background color you can use DrawImage()
                     GadgetWidth(canvas_ID)/2*DR-ImageWidth(image_ID)/2,
                     GadgetHeight(canvas_ID)*DR/2-100*DR)
      FreeImage(image_ID) ; After any output the image (frame) delete it or you get a memory leak
    EndIf
    DrawText(10, 10, Str(GetValueOdometer_OD()))
    DrawText(10, 40, GetAMPM_OD())
    DrawText(10, 110, "Auto Delay "+Str(delay))
    StopDrawing()
    
  ForEver
CompilerEndIf

The first rolling numbers Desktop Clock for PB - All OS - x64/x86 - DPI aware

The odometer module is necessary,

I think it is a good advertisement for PureBasic.

The clock may be edited and distributed free of charge as you wish.
The text in the info file may be extended, but it must not be removed or changed.

The size of the clock can be preset or changed immediatelly.
Look also in the info of the clock, its all very simple. :wink:

Have fun with it.
Image

Code: Select all

XIncludeFile("./Game_Counter_Odometer_Digital_clock.pbi")

; ########################## Desktop digital clock #############################
EnableExplicit

UseModule Odometer_OD

InitOdometer_OD()

Define DR.d=DesktopResolutionX()
Define file, menu_activ, home$=GetHomeDirectory()+"Sakis_digi_clock"

If FileSize(home$)>0
  file=ReadFile(#PB_Any, home$)
  Define window_x=ReadLong(file)
  Define window_y=ReadLong(file)
  Define switch_colors=ReadByte(file)
  Define gradient_color=ReadByte(file)
  Define ampm_mode=ReadByte(file)
  Define change_size_percent=ReadAsciiCharacter(file)
  CloseFile(file)
EndIf 
If Not file : Define flag=#PB_Window_ScreenCentered : EndIf

If switch_colors : SetFrameColor_OD(#Green) : Define used_frame_color=#Green : SetCharColor_OD(#Yellow)
Else
  used_frame_color=#Red
EndIf

If switch_colors : SetFrameColor_OD(#Green) : SetCharColor_OD(#Yellow) : EndIf

If gradient_color : UseGradientColor_OD(1) : Else : UseGradientColor_OD(0) : EndIf

If ampm_mode : UseAMPM_OD(1) : Else : UseAMPM_OD(0) : EndIf

Select change_size_percent
  Case 60  : ChangeSizePercent_OD(60)
  Case 70  : ChangeSizePercent_OD(71)
  Case 80  : ChangeSizePercent_OD(81)
  Case 90  : ChangeSizePercent_OD(89)
  Case 100 : ChangeSizePercent_OD(100)
  Case 110 : ChangeSizePercent_OD(110)
  Case 120 : ChangeSizePercent_OD(120)
  Case 130 : ChangeSizePercent_OD(130)
  Case 140 : ChangeSizePercent_OD(140)
  Case 150 : ChangeSizePercent_OD(150)
  Case 160 : ChangeSizePercent_OD(160)
EndSelect

CompilerIf #PB_Compiler_OS=#PB_OS_MacOS : menu_activ=12 : CompilerElse : menu_activ=1 : CompilerEndIf

Define window_ID=OpenWindow(#PB_Any, window_x, window_y,
                            GetFrameWidth_OD()/DR, GetFrameHeight_OD()/DR+MenuHeight()-1+menu_activ, " Adjust now",
                            flag|#PB_Window_SystemMenu|#PB_Window_Tool)
AddWindowTimer(window_ID, 1, 500)
If file : HideWindow(window_ID, 1) : EndIf
Define canvas_ID=CanvasGadget(#PB_Any, 0, 0, WindowWidth(window_ID), WindowHeight(window_ID))

Define button_1_state, button_2_state, button_3_state, change_window=1, menu_, mode$

Macro menu
  menu_=CreateMenu(#PB_Any , WindowID (window_ID) )
  MenuTitle("Menu")
  MenuItem(1, "Switch Mode 12h/24h")
  MenuItem(2, "Switch Colors")
  MenuItem(3, "GradientColor on/off")
  MenuItem(4, "Info")
  MenuBar()
  MenuBar()
  MenuItem(20, "Finish the clock")
  MenuTitle("Size")
  MenuItem(21, "Size 1")
  MenuItem(22, "Size 2")
  MenuItem(23, "Size 3")
  MenuItem(24, "Size 4")
  MenuItem(25, "Size 5")
  MenuItem(26, "Size 6")
  MenuItem(27, "Size 7")
  MenuItem(28, "Size 8")
  MenuItem(29, "Size 7")
EndMacro
menu

Macro Common_1
  If IsWindow(window_ID)
    window_x=WindowX(window_ID) : window_y=WindowY(window_ID)
    If IsMenu(menu_) : FreeMenu(menu_) : EndIf
    FreeGadget(canvas_ID) ; Mac need this or it crash with VM
    RemoveWindowTimer(window_ID, 1)
    CloseWindow(window_ID)
  EndIf
  CompilerIf #PB_Compiler_OS=#PB_OS_MacOS : menu_activ=12 : CompilerElse : menu_activ=1 :CompilerEndIf
  window_ID=OpenWindow(#PB_Any, window_x, window_y,
                       GetFrameWidth_OD()/DR, GetFrameHeight_OD()/DR+MenuHeight()-1+menu_activ,
                       " Adjust now",
                       #PB_Window_SystemMenu|#PB_Window_Tool)
  AddWindowTimer(window_ID, 1, 500)
  menu
  canvas_ID=CanvasGadget(#PB_Any, 0, 0, WindowWidth(window_ID), WindowHeight(window_ID))
EndMacro        

Macro Common_2
  If IsWindow(window_ID)
    If IsMenu(menu_) : FreeMenu(menu_) : EndIf
    window_x=WindowX(window_ID) : window_y=WindowY(window_ID)
    FreeGadget(canvas_ID) ; Mac need this or it crash with VM
    RemoveWindowTimer(window_ID, 1)
    CloseWindow(window_ID)
  EndIf
  menu_activ=0
  window_ID=OpenWindow(#PB_Any, window_x, window_y,
                       GetFrameWidth_OD()/DR, GetFrameHeight_OD()/DR, "",
                       #PB_Window_BorderLess)
  AddWindowTimer(window_ID, 1, 500)
  canvas_ID=CanvasGadget(#PB_Any, 0, 0, WindowWidth(window_ID), WindowHeight(window_ID))
  change_window=0
  window_x=WindowX(window_ID) : window_y=WindowY(window_ID)
  file=CreateFile(#PB_Any, home$)
  If file
    WriteLong(file, window_x)
    WriteLong(file, window_y)
    WriteByte(file, switch_colors)
    WriteByte(file, gradient_color)
    WriteByte(file, ampm_mode)
    WriteAsciiCharacter(file, change_size_percent)
  CloseFile(file) : EndIf
EndMacro
If file : Common_2 : EndIf

Repeat ; ### Main loop ### 
  
  ; Auto adjust clock rolling speed (delay)
  ; This reduces the cores workload considerably - If a clock is running stand alone, a delay can be increased up to ~10
  Define delay=ClockAutoDelay_OD()
  
  Repeat   ; Get ever all events 
    Define win_event=WindowEvent() ; Add here your events - Just like they always do
    If win_event=#PB_Event_CloseWindow : Common_2 : EndIf
    
    If win_event=#PB_Event_Timer
      If GetClockCycleLength_OD()=-1
        SetWindowTitle(window_ID, " Reduce size")
      Else
        SetWindowTitle(window_ID, " Adjust now")
      EndIf
    EndIf
    
    If win_event=#PB_Event_Menu
      Select EventMenu()
        Case 1
          If ampm_mode
            UseAMPM_OD(0) : Common_1 : ampm_mode=1
          Else
            UseAMPM_OD(1) : Common_1 : ampm_mode=0
          EndIf
          ampm_mode=1-ampm_mode
        Case 2
          If switch_colors
            SetFrameColor_OD(#Red) : SetCharColor_OD(#Yellow)
            used_frame_color=#Red
          Else
            SetFrameColor_OD(#Green) : SetCharColor_OD(#Yellow)
            used_frame_color=#Green
          EndIf
          switch_colors=1-switch_colors
        Case 3
          If gradient_color
            UseGradientColor_OD(0)
          Else
            UseGradientColor_OD(1)
          EndIf
          gradient_color=1-gradient_color
        Case 4
          CompilerIf #PB_Compiler_OS=#PB_OS_MacOS
            MessageRequester(" Saki's Digi clock", "Free for use and free distribution"+#LF$+"This is a part of GFX_Wizzard_BF"+#LF$+
                                                   "You find the settings file in your home folder"+#LF$+#LF$+
                                                   "GradientColor on Mac is emulated and generates"+#LF$+
                                                   "quite high load, you can disable it"+#LF$+#LF$+                                       
                                                   "Created with PureBasic")
          CompilerElse
            MessageRequester(" Saki's Digi clock", "Free for use and free distribution"+#LF$+"This is a part of GFX_Wizzard_BF"+#LF$+
                                                   "You find the settings file in your home folder"+#LF$+#LF$+                                     
                                                   "Created with PureBasic")
          CompilerEndIf
        Case 20 : End
        Case 21 : ChangeSizePercent_OD(60)  : Common_1 : change_size_percent=60
        Case 22 : ChangeSizePercent_OD(71)  : Common_1 : change_size_percent=70
        Case 23 : ChangeSizePercent_OD(81)  : Common_1 : change_size_percent=80
        Case 24 : ChangeSizePercent_OD(89)  : Common_1 : change_size_percent=90
        Case 25 : ChangeSizePercent_OD(100) : Common_1 : change_size_percent=100
        Case 26 : ChangeSizePercent_OD(110) : Common_1 : change_size_percent=110
        Case 27 : ChangeSizePercent_OD(120) : Common_1 : change_size_percent=120
        Case 28 : ChangeSizePercent_OD(130) : Common_1 : change_size_percent=130
        Case 29 : ChangeSizePercent_OD(140) : Common_1 : change_size_percent=140
      EndSelect 
    EndIf
    If win_event=#PB_Event_Gadget
      Select EventGadget()
        Case canvas_ID
          If Not menu_activ
            If GetGadgetAttribute(canvas_ID ,#PB_Canvas_Buttons)&#PB_Canvas_LeftButton
              window_x=WindowX(window_ID) : window_y=WindowY(window_ID)
              If IsMenu(menu_) : FreeMenu(menu_) : EndIf
              FreeGadget(canvas_ID) ; Mac need this or it crash with VM
              RemoveWindowTimer(window_ID, 1)
              CloseWindow(window_ID)
              If change_window And EventType()=#PB_EventType_LeftButtonDown
                window_ID=OpenWindow(#PB_Any, window_x, window_y,
                                     GetFrameWidth_OD()/DR, GetFrameHeight_OD()/DR, "",
                                     #PB_Window_BorderLess)
                change_window=0
              Else
                CompilerIf #PB_Compiler_OS=#PB_OS_MacOS : menu_activ=12 : CompilerElse : menu_activ=1 :CompilerEndIf
                window_ID=OpenWindow(#PB_Any, window_x, window_y,
                                     GetFrameWidth_OD()/DR, GetFrameHeight_OD()/DR+MenuHeight()-1+menu_activ, " Adjust now",
                                     #PB_Window_SystemMenu|#PB_Window_Tool)
                menu
              EndIf
              canvas_ID=CanvasGadget(#PB_Any, 0, 0, WindowWidth(window_ID), WindowHeight(window_ID))
              AddWindowTimer(window_ID, 1, 500)
              change_window=1
            EndIf
          EndIf
      EndSelect 
    EndIf 
  Until Not win_event
  
  Define image_ID=DrawOdometer_OD() ; Create the frames for output as image - Alpha Channel supported
                                    ; You need ever to check if an image is available for output
  StartDrawing(CanvasOutput(canvas_ID))
  If IsImage(image_ID) ; You need ever to check if an image is available for output
    DrawImage(ImageID(image_ID), 0, 0) ; Output the image (frame) - With visible background color you can use DrawImage()
                                       ; DrawText(5, 5, Str(delay))       ; Show the used auto delay
    FreeImage(image_ID)                ; After any output the image (frame) delete it or you get a memory leak
  EndIf
  StopDrawing()
ForEver
Last edited by Saki on Tue Apr 06, 2021 7:01 pm, edited 153 times in total.
地球上の平和
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: Game Counter - Odometer

Post by BarryG »

Thanks, and much smoother than your animated GIF shows.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Game Counter - Odometer

Post by Saki »

Thank you Barry,
check in sometimes, I'm still optimizing the code.
地球上の平和
Mindphazer
Enthusiast
Enthusiast
Posts: 340
Joined: Mon Sep 10, 2012 10:41 am
Location: Savoie

Re: Game Counter - Odometer

Post by Mindphazer »

Hi,
thanks for this code, but i have an issue on MacOS (11.2 Big Sur + PB 5.73) :
Image
MacBook Pro 14" M1 Pro - 16 Gb - MacOS 14 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Game Counter - Odometer

Post by Saki »

Hi Mindphazer.
This was the expected behavior under Mac OS.
Now it works.
地球上の平和
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Game Counter - Odometer

Post by Kwai chang caine »

Works very well :D
Thanks for sharing this nice counter :shock: 8)
ImageThe happiness is a road...
Not a destination
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Game Counter - Odometer

Post by Saki »

Many thanks Kwai.

Code updated

Code optimized, massive speed up.

The Counter is now freely scalable with one simple percent based parameter.
地球上の平和
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Game Counter - Odometer

Post by Saki »

Code updated - Main Update

Many new features added.

Look the first post.

The code is now final.

Have Fun. :wink:
地球上の平和
fluent
User
User
Posts: 68
Joined: Sun Jan 24, 2021 10:57 am

Re: Game Counter - Odometer

Post by fluent »

That's a very good job! Thanks!
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: Game Counter - Odometer

Post by Keya »

looks super sexy with the gradient fill, great work
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Game Counter - Odometer

Post by Saki »

Hi @fluent and @Keya

I am glad that you like it.
I have divided the code into macros now and added "odo" to the end of some variables, so it is now consistent.
You can fold the code now, there are only 65 lines left.
Now you can see directly how it works and you can easily import the code into any other code.
It probably takes only a few minutes to get the code running in another code without problems.

Best Regards Saki
Last edited by Saki on Wed Mar 10, 2021 9:48 pm, edited 1 time in total.
地球上の平和
JHPJHP
Addict
Addict
Posts: 2129
Joined: Sat Oct 09, 2010 3:47 am
Contact:

Re: Game Counter - Odometer

Post by JHPJHP »

Windows 10 Pro / PureBasic 5.73 LTS (x86/x64)

NOTE: Most of the bugs I found occurred using PureBasic x86, but I only did a few minutes of testing.

1. Set number_of_chars_odo to 10.
- irregular output number
- border alignment is off
-- remove alpha option (char_color_odo) to better view the issue
2. Set output_odo to a large value.
- 2147483647: cannot handle large values
- 2147483637: crash (might be a separate issue)
3. Set used_font_odo__odo$ to verdana.
- number partially outside/hidden by border
-- remove alpha option (char_color_odo) to better view the issue

NB*: I will not be available for any further testing or discussion.
Mindphazer
Enthusiast
Enthusiast
Posts: 340
Joined: Mon Sep 10, 2012 10:41 am
Location: Savoie

Re: Game Counter - Odometer

Post by Mindphazer »

Again, an issue on MacOS Big Sur :
Image
MacBook Pro 14" M1 Pro - 16 Gb - MacOS 14 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
User avatar
HeX0R
Addict
Addict
Posts: 980
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: Game Counter - Odometer

Post by HeX0R »

Saki wrote:[...]
Now you can see directly how it works and you can easily import the code into any other code.
It probably takes only a few minutes to get the code running in another code without problems.
:lol:
The output is cool, no question, but how on earth should this thing be easily integratable into own code?
I personally never use any defines in my codes (and even if I would, I for sure wouldn't use around 50 of them), and I also don't see a reason to use such huge macros instead of encapsulated procedures, or even better put it into a module (wasn't that the plan initially? That's what I'd call reusability).

And that WindowEvent() : Delay(1) thing is terrible!
The odometer will freeze when you move the window, you should use a timer for that.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: Game Counter - Odometer

Post by Saki »

Hi all,
Thank you very much for the testing and the evaluation.
I hadn't done an x86 adjustment, so that can't work if the numbers get too big.
Something went wrong with the last adjustment of the variables, I undid that, it's not necessary.
The clipping trims the overhanging numbers, but not the frame, so there are disproportionate frames,
I have to adjust that.
The clipped numbers on special fonts are caused by the clipping.
I still need to adjust that, it's not a bug per se, the clipping just needs to be removed or reset.
I only put the macros in to give the user a better overview of how it works,
They can also be easily removed.
The problems between the OS were bigger than expected, you have to go back and forth and test everything again,
and it's easy to find a new bug or miss a bug.

Well, primarily the code can be imported easily, especially since only one such counter is used most of the time.
The macros are in fact only a preliminary stage for a better overview.
I will go step by step, otherwise I won't get a good grip on the bugs...

The module is the next step.

If the code runs absolutely error-free, I'll try to make a module out of it.
It was important to implement everything I wanted, to localise and eliminate errors.

At the weekend I'll post another code, I've already fixed all the bugs.

I still have to make the adjustments for the clipping, then it's ready.
It's late, I won't do much today.
Please give me one or two days, then I'll post the new code.
Please test it again.

I'll look at the module when I find no more bugs.
Primarily I want to make a module out of it, but then I have to make some variables static
and make it do what it's supposed to do.
A first quick try yesterday didn't work, it needs some time and everything needs to be rethought.

@Mindparzer, I don't see your images, the links don't work.
I also have BigSur running here, so it's not a problem.
The problem is the time involved, going back and forth between OS and testing everything possible again.

I'm trying to implement everything.
Any help is appreciated, it just takes more time than I have.

It was a spontaneous idea to make this tool, everything was implemented too quickly, mistakes happen.

Thanks again to all.
地球上の平和
Post Reply