I drew digits on squared paper and put their coordinates into data, plotting them as required pixel by pixel. This seemed to work better for me than writing text to graphics.
Note, the code has an auto-restart section that detects if it's changed and saved, so if you edit it, you can just save and it will re-run.
EDIT: Just realised removing standard menu items is dangerous at this stage of development, as if something goes wrong you might not be able to quit from the script, so have left standard menu in place in this version...
EDIT: Apparently it's still buggy, as you may see below. I'm working on a fix.
Also, I forgot to say that this needs the GDI+ Library by tic (Tariq Porter). You can download that here https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6517
You should rename the file Gdip.ahk (from Gdip_All.ahk) and copy it into your "\Lib" folder in the main installation folder for Autohotkey.
EDIT: Ok, this might have fixed it (code edited in this version)...
From here, I'll keep adding notes about updates. I'll update the code in the box here, unless there's a time limit on editing posts. I'll also number versions in the code and with related changes noted here...so you can always check if you've got the latest...
NB: Although version numbers begin at 1...., it should be understood that this is under development (strict convention says they should be 0...), and use of this script is at your own risk, although it's carefully coded and shouldn't cause problems.
v1.02 A minor tidy-up. The last version (before I numbered them) fixed the need to save the image to disc.
v1.03 Added: Options dialog with colour settings stored in ini file; Copy to clipboard a few date formats; Error handler for problem icon loading (not ideal, but will save to error log and then restart the app). Thanks to iPhilip for Colour Chooser routine.
v1.04 Removed Menu, Tray, UseErrorLevel as this seemed to cause freeze instead of error trap and reload.
v1.05 FIXED the crash! This is a small update that should fix the crashing issue when loading the icon. Hopefully, I'll have another update soon with reminders.
Code: Select all
; TrayClock v1.05 by Ahketype. Feel free to share, edit, etc. Author acknowledgement appreciated.
; Updates, info at https://www.autohotkey.com/boards/viewtopic.php?f=6&t=60416
; A digital clock as a notification icon, to replace the standard windows clock if so wished.
; It doesn't remove the Windows clock - to do this, R-click on empty bit of taskbar > Properties > System Icons.
; Can show hours & minutes (one above other) or minutes & seconds.
; When hrs & mins, intermittently switches to day of week and day of month indicators.
; Edited from gdi+ ahk tutorial written by tic (Tariq Porter); many thanks, tic!
; Requires Gdip.ahk by tic, either in your Lib folder as standard library or using #Include
; GDI+ Library, see: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6517
; Thanks also to iPhilip for Colour Chooser routine.
ver := 1.05
SetWorkingDir, % A_ScriptDir
#persistent
#SingleInstance, Force
#NoEnv
; Set file attribute to avoid reloading on first run.
; When script changed thereafter and saved, will reload.
FileSetAttrib, -A, %A_ScriptFullPath%
OnExit, Exitsub
; Tray menus
; Menu, Tray, UseErrorLevel
Menu, Copy, Add, yyyyMMdd, CopyYearMoDa
Menu, Copy, Add, yyyyMMdd-HHmm, CopyYearMoDaHrMi
Menu, Copy, Add, dd/MM/yyyy, CopyDaMoYear
Menu, Tray, MainWindow ; for compiled script
Menu, Tray, Add
Menu, Tray, Add
Menu, Tray, Add, Copy to clipboard, :Copy
Menu, Tray, Add, System Clock, TimeDateCpl
Menu, Tray, Add, Options, Opts
Menu, Tray, Add, Minutes and seconds, Showms
Menu, Tray, Default, Minutes and seconds
cal := 1 ; Initialize counter for showing day
CustomColors := [] ; todo: Research comdlg32\ChooseColor
; ==================================
; Default settings in case INI file does not exist, otherwise will read ini.
; These colours use ARGB, where the first hex byte indicates opacity 00-FF
timecolour := 0xfffffff0 ; hours and minutes
timecolour2:= 0xffc0ffa0 ; colour of seconds
daycolour := 0xffff2255 ; date of the month
backcolour := 0x00000000 ; background of icon
; Yet to add to ini file (edit here for now)...
clockmode := "hm" ; Whether to show hours and minutes ("hm") or minutes and seconds ("ms") by default
interval := 100 ; How often (milliseconds) to check if update needed
calfreq := 4 ; How often to show day (secs). 2 = on/off, <2 = always, 5000000000 = not in your lifetime!
; ==============================================================================
; Create or read settings from ini file
If !FileExist("trayclock.ini")
{
FileAppend, [colours]`ntimecolour=%timecolour%`ntimecolour2=%timecolour2%`ndaycolour=%daycolour%`nbackcolour=%backcolour%, trayclock.ini
} else {
IniRead, timecolour, trayclock.ini, colours, timecolour
IniRead, timecolour2, trayclock.ini, colours, timecolour2
IniRead, daycolour, trayclock.ini, colours, daycolour
IniRead, backcolour, trayclock.ini, colours, backcolour
}
; Split RGB component of colours from A, since only RGB used in standard colour dialog
gosub, Splitcols
; Single figure xy (space delim) coordinates of points making up digits 0-9
; These make up all digital readout plotted to image.
d0 := "01 02 03 04 05 10 11 12 13 14 15 16 20 26 30 36 40 46 50 51 52 53 54 55 56 61 62 63 64 65"
d1 := "20 26 30 31 32 33 34 35 36 40 41 42 43 44 45 46 56"
d2 := "04 05 06 10 13 14 15 16 20 23 26 30 33 36 40 43 46 50 51 52 53 56 61 62 66"
d3 := "10 16 20 23 26 30 33 36 40 43 46 50 51 52 53 54 55 56 61 62 64 65"
d4 := "03 04 12 13 14 21 22 24 30 31 34 40 41 42 43 44 45 46 50 51 52 53 54 55 56 64"
d5 := "01 02 03 10 11 12 13 16 20 23 26 30 33 36 40 43 46 50 53 54 55 56 60 64 65"
d6 := "01 02 03 04 05 10 11 12 13 14 15 16 20 23 26 30 33 36 40 43 46 50 53 54 55 56 64 65"
d7 := "10 20 25 26 30 33 34 35 36 40 42 43 44 50 51 52 60 61"
d8 := "01 02 04 05 10 11 12 13 14 15 16 20 23 26 30 33 36 40 43 46 50 51 52 53 54 55 56 61 62 64 65"
d9 := "01 02 10 11 12 13 16 20 23 26 30 33 36 40 43 46 50 51 52 53 54 55 56 61 62 63 64 65"
; Coords of days of the week, e.g. SU MO TU, as xxy (since x needs 2 digits, y is only in range 0-6)
dow1 := "001 002 005 010 011 012 013 015 016 020 023 026 030 033 036 040 043 046 050 051 053 054 055 056 061 064 065 080 081 082 083 084 085 090 091 092 093 094 095 096 106 116 126 130 131 132 133 134 135 136 140 141 142 143 144 145"
dow2 := "000 001 002 003 004 005 006 010 011 012 013 014 015 016 021 022 032 033 041 042 050 051 052 053 054 055 056 060 061 062 063 064 065 066 081 082 083 084 085 090 091 092 093 094 095 096 100 106 110 116 120 126 130 131 132 133 134 135 136 141 142 143 144 145"
dow3 := "000 010 020 021 022 023 024 025 026 030 031 032 033 034 035 036 040 050 080 081 082 083 084 085 090 091 092 093 094 095 096 106 116 126 130 131 132 133 134 135 136 140 141 142 143 144 145"
dow4 := "000 001 002 003 004 005 006 010 011 012 013 014 015 016 024 025 033 034 044 045 050 051 052 053 054 055 056 060 061 062 063 064 065 066 080 081 082 083 084 085 086 090 091 092 093 094 095 096 100 103 106 110 113 116 120 123 126 130 133 136 140 146"
dow5 := "000 010 020 021 022 023 024 025 026 030 031 032 033 034 035 036 040 050 080 081 082 083 084 085 086 090 091 092 093 094 095 096 103 113 123 130 131 132 133 134 135 136 140 141 142 143 144 145 146"
dow6 := "000 001 002 003 004 005 006 010 011 012 013 014 015 016 020 023 030 033 040 043 050 053 060 080 081 082 083 084 085 086 090 091 092 093 094 095 096 100 103 110 113 114 115 120 123 124 125 130 131 132 133 135 136 141 142 145 146"
dow7 := "001 002 005 010 011 012 013 015 016 020 023 026 030 033 036 040 043 046 050 051 053 054 055 056 061 064 065 081 082 083 084 085 086 090 091 092 093 094 095 096 100 103 110 113 120 123 130 131 132 133 134 135 136 141 142 143 144 145 146"
; Uncomment next line if Gdip.ahk is not in your standard library (and get Gdip.ahk).
; #Include, Gdip.ahk
; Start gdi+
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
; Create a 16x16 pixel gdi+ bitmap
pBitmap := Gdip_CreateBitmap(16, 16)
; Get a pointer to the graphics of the bitmap, for use with drawing functions
G := Gdip_GraphicsFromImage(pBitmap)
; Main GUI definition (for later use)
Gui, New, , Main
Gui, Add, Text, , Main gui window
; Options GUI definition
Gui, Options:New, HwndIdOpts
Gui, Options:+Owner
Gui, Options:+OwnDialogs
Gui, Add, GroupBox, w380 h180 y20, Colours
Gui, Add, Text, xp+42 yp+20, Basic Colour
Gui, Add, Text, xp+190 yp, Opacity
Gui, Add, Progress, h22 w23 x20 y65 vTimeco c%timeRGB% +BackgroundTrans, 100
Gui, Add, Progress, h22 w23 yp+31 vTimeco2 c%timeRGB2% +BackgroundTrans, 100
Gui, Add, Progress, h22 w23 yp+31 vDayco c%dayRGB% +BackgroundTrans, 100
Gui, Add, Progress, h22 w23 yp+31 vBackco c%backRGB% +BackgroundTrans, 100
Gui, Add, Button, gSetTimeColour xp+30 y64 w100 h25, &Hours && Mins
Gui, Add, Button, gSetTimeColour2 wp hp, &Seconds
Gui, Add, Button, gSetDayColour wp hp, &Day
Gui, Add, Button, gSetBackColour wp hp, &Background
Gui, Add, Slider, xp+120 y62 w200 h22 Range0-255 TickInterval32 Left vtimeA gUpdateTimeA, %timeA%
Gui, Add, Slider, xp yp+31 w200 h22 Range0-255 TickInterval32 Left vtimeA2 gUpdateTimeA2, %timeA2%
Gui, Add, Slider, xp yp+31 w200 h22 Range0-255 TickInterval32 Left vdayA gUpdateDayA, %dayA%
Gui, Add, Slider, xp yp+31 w200 h22 Range0-255 TickInterval32 Left vbackA gUpdateBackA, %backA%
Gui, Add, Button, x50 y450 w120 h25 gRevertOpts, &Revert
Gui, Add, Button, x240 y450 w120 h25 gCloseOpts, &Accept && Close
SetTimer, Maintimer, %interval% ; Main timer checks if update needed at these milliseconds intervals.
return
; ------------------------------ End of init. section-------------
; ================================================================
; Open Main Window
Window:
Gui, Show, xCenter yCenter w800 h500, Main Window
return
; Open options window
Opts:
; Keep copies of vars to revert to if changes not accepted in dialog
Rtimeco := timecolour, Rtimeco2 := timecolour2, Rdayco := daycolour, Rbackco := backcolour
Gui, Options:Show, xCenter yCenter w400 h500, Options
return
CloseOpts:
; Write vars to ini file and close win
IniWrite, timecolour=%timecolour%`ntimecolour2=%timecolour2%`ndaycolour=%daycolour%`nbackcolour=%backcolour%, trayclock.ini, colours
WinClose
return
RevertOpts:
; Reset vars from saved copies and update controls
timecolour := Rtimeco, timecolour2 := Rtimeco2, daycolour := Rdayco, backcolour := Rbackco
gosub, Splitcols
GuiControl, +c%timeRGB%, Timeco
GuiControl, +c%timeRGB2%, Timeco2
GuiControl, +c%dayRGB%, Dayco
GuiControl, +c%backRGB%, Backco
GuiControl, , timeA, %timeA%
GuiControl, , timeA2, %timeA2%
GuiControl, , dayA, %dayA%
GuiControl, , backA, %backA%
return
; Four subroutines call Windows colour chooser dialog and update vars, controls
SetTimeColour:
Result := ChooseColor(timecolour & 0xFFFFFF, , IdOpts)
if Result =
return
timecolour := Result + (timeA << 24)
timeRGB := Format("{1:X}", (timecolour & 0xffffff))
GuiControl, +c%timeRGB%, Timeco
return
SetTimeColour2:
Result := ChooseColor(timecolour2 & 0xFFFFFF, , IdOpts)
if Result =
return
timecolour2 := Result + (timeA2 << 24)
timeRGB2 := Format("{1:X}", (timecolour2 & 0xffffff))
GuiControl, +c%timeRGB2%, Timeco2
return
SetDayColour:
Result := ChooseColor(daycolour & 0xFFFFFF, , IdOpts)
if Result =
return
daycolour := Result + (dayA << 24)
dayRGB := Format("{1:X}", (daycolour & 0xffffff))
GuiControl, +c%dayRGB%, Dayco
return
SetBackColour:
Result := ChooseColor(backcolour & 0xFFFFFF, , IdOpts)
if Result =
return
backcolour := Result + (backA << 24)
backRGB := Format("{1:X}", (backcolour & 0xffffff))
GuiControl, +c%backRGB%, Backco
return
; Four subroutines deal with slider changes, AA bytes of AARRGGBB
UpdateTimeA:
timecolour := (timecolour & 0xffffff) + (timeA << 24)
return
UpdateTimeA2:
timecolour2 := (timecolour2 & 0xffffff) + (timeA2 << 24)
return
UpdateDayA:
daycolour := (daycolour & 0xffffff) + (dayA << 24)
return
UpdateBackA:
backcolour := (backcolour & 0xffffff) + (backA << 24)
return
; Toggle mode from hrs/mins(+day) to mins secs, and rename menu item
Showms:
if (clockmode = "hm")
{
Menu, Tray, Rename, Minutes and seconds, Hours and minutes
clockmode = ms
}
else
{
Menu, Tray, Rename, Hours and minutes, Minutes and seconds
clockmode = hm
}
gosub, Plotclock ; for immediate update
return
Maintimer:
If (secs = A_Sec) ; Check if seconds have changed.
return
; If script file changed, reload (handy while programming)
FileGetAttrib, attribs, %A_ScriptFullPath%
IfInString, attribs, A
{
posX = %A_CaretX%
posY = %A_CaretY%
ToolTip, Automatically reloading`nupdated script!, %posX%, %posY%
Sleep, 100
Reload
}
gosub, Plotclock
return
Plotclock:
; Get hhmmss digits
secs := A_Sec
mins := A_Min
ours := A_Hour ; "ours" just avoids syntax highlighting
day := A_DD
daytens := SubStr(day, 1, 1)
dayunits := SubStr(day, 2, 1)
hrtens := SubStr(ours, 1, 1)
hrunits := SubStr(ours, 2, 1)
mintens := SubStr(mins, 1, 1)
minunits := SubStr(mins, 2, 1)
sectens := SubStr(secs, 1, 1)
secunits := SubStr(secs, 2, 1)
; Build the new image...
; Clear the graphic. If fully transparent, will match taskbar
Gdip_GraphicsClear(G, backcolour)
if (clockmode = "hm")
gosub H_M ; Print hours above, minutes below
else if (clockmode = "ms")
gosub M_S ; Print minutes above, seconds below
; Get handle of icon
hIcon := Gdip_CreateHICONFromBitmap(pBitmap)
; Update icon (try, since did fail: hopefully now fixed)
try
Menu, Tray, Icon, HICON:%hIcon%
catch, e
{
FormatTime, tipstring, , HH:mm dddd dd MMMM
FileAppend, v%ver% err:%e% (loadicon) at %tipstring%`n, errlog.txt
Reload
}
return
; Update tool tip with time and date
FormatTime, tipstring, , HH:mm dddd dd MMMM
Menu, Tray, Tip, %tipstring%
return
H_M:
if cal < %calfreq% ; Every calfreq seconds, do 'else' part...
{
++cal
; Set hours and minutes as individual pixels in bitmap...
; Hour tens
Loop, Parse, d%hrtens%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x, y, timecolour)
}
; Hour units
Loop, Parse, d%hrunits%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x+9, y, timecolour)
}
; Minute tens
Loop, Parse, d%mintens%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x, y+9, timecolour)
}
; Minute units
Loop, Parse, d%minunits%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x+9, y+9, timecolour)
}
} else {
; Show day of week and of month
cal := 1
; Day of Week
Loop, Parse, dow%A_WDay%, %A_Space%
{
x := SubStr(A_LoopField, 1, 2)
y := SubStr(A_LoopField, 3, 1)
Gdip_SetPixel(pBitmap, x+1, y, daycolour)
}
; Day tens
Loop, Parse, d%daytens%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x, y+9, daycolour)
}
; Day units
Loop, Parse, d%dayunits%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x+9, y+9, daycolour)
}
}
return
M_S:
; Set minutes and seconds as individual pixels in bitmap
; Minute tens
Loop, Parse, d%mintens%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x, y, timecolour)
}
; Minute units
Loop, Parse, d%minunits%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x+9, y, timecolour)
}
; Second tens
Loop, Parse, d%sectens%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x, y+9, timecolour2)
}
; Second units
Loop, Parse, d%secunits%, %A_Space%
{
x := SubStr(A_LoopField, 1, 1)
y := SubStr(A_LoopField, 2, 1)
Gdip_SetPixel(pBitmap, x+9, y+9, timecolour2)
}
return
; Runs system time and date control panel app
TimeDateCpl:
Run, control timedate.cpl
return
; Allows editing of this script.
Editscript:
Edit
return
; Copy to clipboard
CopyYearMoDa:
FormatTime, Clipboard, , yyyyMMdd
return
CopyYearMoDaHrMi:
FormatTime, Clipboard, , yyyyMMdd-HHmm
return
CopyDaMoYear:
FormatTime, Clipboard, , dd/MM/yyyy
return
; Split colours to A, RGB components
Splitcols:
timeRGB := Format("{1:X}", (timecolour & 0xffffff)), timeA := timecolour >> 24
timeRGB2 := Format("{1:X}", (timecolour2 & 0xffffff)), timeA2 := timecolour2 >> 24
dayRGB := Format("{1:X}", (daycolour & 0xffffff)), dayA := daycolour >> 24
backRGB := Format("{1:X}", (backcolour & 0xffffff)), backA := backcolour >> 24
return
; Cleanup Gdip memory before exit.
Exitsub:
; The bitmap can be deleted
Gdip_DisposeImage(pBitmap)
; The graphics may now be deleted
Gdip_DeleteGraphics(G)
; ...and gdi+ may now be shutdown
Gdip_Shutdown(pToken)
ExitApp
; Call Windows Colour Chooser, adapted from script by iPhilip
ChooseColor(StartingRGB := 0x0, CustomRGBs := "", hWnd := 0x0, Flags := 0x3) { ; CC_RGBINIT = 0x1, CC_FULLOPEN = 0x2
VarSetCapacity(CustomColors, 64, 0)
NumPut(VarSetCapacity(CC, A_PtrSize = 8 ? 72 : 36, 0), CC, 0, "UInt")
NumPut(hWnd ? hWnd : A_ScriptHwnd, CC, A_PtrSize = 8 ? 8 : 4, "Ptr")
NumPut(COLORREF(StartingRGB), CC, A_PtrSize = 8 ? 24 : 12, "UInt")
NumPut(&CustomColors, CC, A_PtrSize = 8 ? 32 : 16, "Ptr")
NumPut(Flags, CC, A_PtrSize = 8 ? 40 : 20, "UInt")
if IsObject(CustomRGBs)
for each, RGB in CustomRGBs
NumPut(COLORREF(RGB), CustomColors, (each-1)*4, "UInt")
if DllCall("comdlg32\ChooseColor", "Ptr", &CC, "Int") {
if IsObject(CustomRGBs)
Loop, 16
CustomRGBs[A_Index] := COLORREF(NumGet(CustomColors, (A_Index-1)*4, "UInt"))
Offset := A_PtrSize = 8 ? 24 : 12
; Return Format("{:02X}{:02X}{:02X}", NumGet(CC, Offset, "UChar"), NumGet(CC, Offset+1, "UChar"), NumGet(CC, Offset+2, "UChar"))
Return 256 * 256 * NumGet(CC, Offset, "UChar") + 256 * NumGet(CC, Offset+1, "UChar") + NumGet(CC, Offset+2, "UChar")
}
}
COLORREF(RGB) { ; 0xRRGGBB - > 0xBBGGRR -> 0xRRGGBB
Return ((RGB & 0xFF) << 16) + (RGB & 0xFF00) + ((RGB >> 16) & 0xFF)
}
ahketype