; drawing code for aclock ; ; Copyright (c) 2003 Thomas Mathys ; killer@vantage.ch ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ; %ifndef _DRAW_INC %define _DRAW_INC TMR1_FACTOR dd 0.45 TMR2_FACTOR dd 0.426315789 SECR_FACTOR dd 0.378947368 MINR_FACTOR dd 0.355263158 HOURR_FACTOR dd 0.189473684 DATE_FACTOR dd 0.1 monthNames: db "Jan" db "Feb" db "Mar" db "Apr" db "May" db "Jun" db "Jul" db "Aug" db "Sep" db "Oct" db "Nov" db "Dec" ;******************************************************************** ; draws the clock ; input : nothing ; output : nothing ; destroys : nothing ;******************************************************************** drawClock: %push drawClock_context %stacksize flat %assign %$localsize 0 %local i:dword, \ TMR1X:dword, \ TMR1Y:dword, \ TMR2X:dword, \ TMR2Y:dword, \ SECRX:dword, \ SECRY:dword, \ MINRX:dword, \ MINRY:dword, \ HOURRX:dword, \ HOURRY:dword, \ workwidth:dword, \ workheight:dword, \ foo:dword enter %$localsize,0 pushad pushfd ; get window dimensions mov eax,MOS_SC_GETPROCESSINFO mov ebx,procInfo mov ecx,-1 int 0x40 ; calculate work area size (width/height = ecx/edx) ; if the work area is too small (maybe the window is shaded) ; we don't draw anything. mov eax,MOS_SC_WINDOWPROPERTIES mov ebx,4 ; get skin height (eax) int 0x40 mov ecx,[procInfo + MOS_PROCESSINFO.wndWidth] sub ecx,MOS_WND_SKIN_BORDER_LEFT+MOS_WND_SKIN_BORDER_RIGHT mov edx,[procInfo + MOS_PROCESSINFO.wndHeight] sub edx,eax sub edx,MOS_WND_SKIN_BORDER_BOTTOM cmp ecx,0 ; width too small ? jle .bye cmp edx,0 ; height too small ? jnle .continue .bye: jmp .byebye .continue: mov [workwidth],ecx ; save for later (for fpu) mov [workheight],edx ; calculate center of clock (x/y = esi/edi) mov esi,[procInfo + MOS_PROCESSINFO.wndWidth] shr esi,1 mov edi,[procInfo + MOS_PROCESSINFO.wndHeight] sub edi,MOS_WND_SKIN_BORDER_BOTTOM sub edi,eax shr edi,1 add edi,eax ; clear work area pushad mov ebx,(MOS_WND_SKIN_BORDER_LEFT)*0x10000 ; x start or ebx,ecx ; width inc ebx mov ecx,eax ; y start shl ecx,16 ; (=skin height) or ecx,edx ; height inc ecx mov edx,[wndColors + MOS_WNDCOLORS.work] mov eax,MOS_SC_DRAWBAR int 0x40 popad ; calculate second hand radii fild dword [workwidth] fmul dword [SECR_FACTOR] fstp dword [SECRX] fild dword [workheight] fmul dword [SECR_FACTOR] fstp dword [SECRY] ; calculate minute hand radii fild dword [workwidth] fmul dword [MINR_FACTOR] fstp dword [MINRX] fild dword [workheight] fmul dword [MINR_FACTOR] fstp dword [MINRY] ; calculate hour hand radii fild dword [workwidth] fmul dword [HOURR_FACTOR] fstp dword [HOURRX] fild dword [workheight] fmul dword [HOURR_FACTOR] fstp dword [HOURRY] ; calculate tick mark radii fild dword [workwidth] fmul dword [TMR1_FACTOR] fstp dword [TMR1X] fild dword [workheight] fmul dword [TMR1_FACTOR] fstp dword [TMR1Y] fild dword [workwidth] fmul dword [TMR2_FACTOR] fstp dword [TMR2X] fild dword [workheight] fmul dword [TMR2_FACTOR] fstp dword [TMR2Y] ; get system clock (edx) mov eax,MOS_SC_GETSYSCLOCK int 0x40 mov edx,eax ; draw second hand push edx mov eax,edx shr eax,16 call bcdbin mov ecx,eax ; save seconds for later push ecx push eax fpush32 0.104719755 ; 2*pi/60 push dword [SECRX] push dword [SECRY] push esi push edi call getHandCoords mov eax,MOS_SC_DRAWLINE shl ebx,16 or ebx,esi shl ecx,16 or ecx,edi mov edx,[wndColors + MOS_WNDCOLORS.workText] int 0x40 pop ecx pop edx ; draw minute hand push edx mov eax,edx shr eax,8 call bcdbin mov edx,60 mul edx add eax,ecx mov ecx,eax ; save for later push ecx push eax fpush32 0.001745329 ; 2*pi/60/60 push dword [MINRX] push dword [MINRY] push esi push edi call getHandCoords mov eax,MOS_SC_DRAWLINE shl ebx,16 or ebx,esi shl ecx,16 or ecx,edi mov edx,[wndColors + MOS_WNDCOLORS.workText] int 0x40 pop ecx pop edx ; draw hour hand push edx mov eax,edx call bcdbin cmp eax,11 ; % 12 (just to be sure) jnae .hoursok sub eax,12 .hoursok: mov edx,60*60 mul edx add eax,ecx push eax fpush32 0.000145444 ; 2*pi/60/60/12 push dword [HOURRX] push dword [HOURRY] push esi push edi call getHandCoords mov eax,MOS_SC_DRAWLINE shl ebx,16 or ebx,esi shl ecx,16 or ecx,edi mov edx,[wndColors + MOS_WNDCOLORS.workText] int 0x40 pop edx ; draw tick marks mov dword [i],11 ; draw 12 marks .drawtickmarks: push dword [i] ; calculate start point fpush32 0.523598776 ; 2*pi/12 push dword [TMR1X] push dword [TMR1Y] push esi push edi call getHandCoords mov eax,ebx ; save in eax and edx mov edx,ecx push dword [i] fpush32 0.523598776 ; 2*pi/12 push dword [TMR2X] push dword [TMR2Y] push esi push edi call getHandCoords shl eax,16 shl edx,16 or ebx,eax ; ebx = x start and end or ecx,edx ; ecx = y start and end mov edx,[wndColors + MOS_WNDCOLORS.workText] mov eax,MOS_SC_DRAWLINE int 0x40 dec dword [i] jns .drawtickmarks %define DATE_WIDTH 48 ; calculate text start position mov eax,[procInfo+MOS_PROCESSINFO.wndWidth] sub eax,DATE_WIDTH ; x = (wndwidth-textwidth)/2 shr eax,1 ; eax = x fild dword [workheight] ; y = DATE_FACTOR*workheight... fmul dword [DATE_FACTOR] mov [foo],edi ; ... + y_clockcenter fiadd dword [foo] fistp dword [foo] mov ebx,[foo] ; ebx = y ; draw text at all ? cmp dword [workwidth],DATE_WIDTH ; text too wide ? jb .goodbye mov ecx,ebx ; text too high ? add ecx,10-1 mov edx,[procInfo+MOS_PROCESSINFO.wndHeight] sub edx,MOS_WND_SKIN_BORDER_BOTTOM cmp ecx,edx jnae .yousuck .goodbye: jmp .bye .yousuck: ; ebx = (x << 16) | y shl eax,16 or ebx,eax ; get date (edi) mov eax,MOS_SC_GETDATE int 0x40 mov edi,eax ; display month mov eax,edi ; get month shr eax,8 call bcdbin ; ebx contains already position mov ecx,[wndColors+MOS_WNDCOLORS.workText] lea edx,[monthNames-3+eax*2+eax]; -3 because eax = 1..12 =] mov esi,3 ; text length mov eax,MOS_SC_WRITETEXT int 0x40 ; display date add ebx,MOS_DWORD(3*6+3,0) mov eax,edi ; get date shr eax,16 call bcdbin mov edx,ebx ; position must be in edx mov ebx,0x00020000 ; number, display two digits mov ecx,eax ; number to display mov esi,[wndColors+MOS_WNDCOLORS.workText] mov eax,MOS_SC_WRITENUMBER int 0x40 ; display year. the way we avoid the y2k bug is even ; simpler, yet much better than in the last version: ; now we simply display the last two digits and let the ; user decide wether it's the year 1903 or 2003 =] add edx,MOS_DWORD(2*6+3,0) mov eax,edi ; get year call bcdbin mov ebx,0x00020000 ; number, display two digits mov ecx,eax ; number to display ; edx contains already position mov esi,[wndColors+MOS_WNDCOLORS.workText] mov eax,MOS_SC_WRITENUMBER int 0x40 .byebye: popfd popad leave ret %pop ;********************************************************** ; bcdbin ; converts a 8 bit bcd number into a 32 bit binary number ; ; in al = 8 bit bcd number ; out eax = 32 bit binary number ; destroys dl,flags ;********************************************************** bcdbin: push edx pushfd mov dl,al ; save bcd number shr al,4 ; convert upper nibble mov ah,10 mul ah and dl,15 ; add lower nibble add al,dl and eax,255 ; ! popfd pop edx ret ;******************************************************************** ; getHandCoords ; calculates the end point of a hand ; ; input (on stack, push from top to bottom): ; ANGLE angle (integer) ; DEG2RAD conversion factor for ANGLE (32 bit real) ; RADIUSX x radius (32 bit real) ; RADIUSY y radius (32 bit real) ; CENTERX x center of the clock (integer) ; CENTERY y center of the clock (integer) ; ; output: ; ebx x coordinate in bits 0..15, bits 16..31 are zero ; ecx y coordinate in bits 0..15, bits 16..31 are zero ; ; destroys: ; nothing ;******************************************************************** getHandCoords: ANGLE equ 28 DEG2RAD equ 24 RADIUSX equ 20 RADIUSY equ 16 CENTERX equ 12 CENTERY equ 8 enter 0,0 pushfd fild dword [ebp+ANGLE] ; get angle fmul dword [ebp+DEG2RAD] ; convert to radians fsincos fmul dword [ebp+RADIUSY] ; -y * radius + clockcy fchs fiadd dword [ebp+CENTERY] fistp dword [ebp+CENTERY] fmul dword [ebp+RADIUSX] ; x * radius + clockcx fiadd dword [ebp+CENTERX] fistp dword [ebp+CENTERX] mov ebx,[ebp+CENTERX] mov ecx,[ebp+CENTERY] popfd leave ret 4*6 %endif