Code:
#PBFORMS CREATED V1.51 '----------------------------------------------------------------------------- ' Calendar with clickable days ' written 13-6-2006 Chris Holbrook for public use ' not properly tested ' only restriction - if you use it, take my name off! ' using PBWin 8.01 & PBForms 1.51 ' ' to run, enter the month (at least 1st 3 digits of english month name) ' and year at the top left and click the button next. ' Clicking each day toggles the background colour. ' terminate with Alt-F4 ' drag with left mouse button down (not on a day). ' ' implementation: ' - each cell in the calendar is a cell in a static control array. ' - there is a corresponding array g_calday() of cell attributes ' - the controls are all subclassed to the same function, but can ' - have different OnClick functions. ' ' changes: ' 13-6-2006 fixed GDI object leak in SubclassStaticProc '------------------------------------------------------------------------------ ' The first line in this file is a PB/Forms metastatement. ' It should ALWAYS be the first line of the file. Other ' PB/Forms metastatements are placed at the beginning and ' end of "Named Blocks" of code that should be edited ' with PBForms only. Do not manually edit or delete these ' metastatements or PB/Forms will not be able to reread ' the file correctly. See the PB/Forms documentation for ' more information. ' Named blocks begin like this: #PBFORMS BEGIN ... ' Named blocks end like this: #PBFORMS END ... ' Other PB/Forms metastatements such as: ' #PBFORMS DECLARATIONS ' are used by PB/Forms to insert additional code. ' Feel free to make changes anywhere else in the file. '------------------------------------------------------------------------------ #COMPILE EXE #DIM ALL '------------------------------------------------------------------------------ ' ** Includes ** '------------------------------------------------------------------------------ #PBFORMS BEGIN INCLUDES #IF NOT %DEF(%WINAPI) #INCLUDE "WIN32API.INC" #ENDIF #PBFORMS END INCLUDES '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Constants ** '------------------------------------------------------------------------------ #PBFORMS BEGIN CONSTANTS %IDD_caldlg = 101 %IDC_LABEL1 = 1001 '* %IDC_LABEL2 = 1002 '* %IDC_LABEL3 = 1003 '* %IDC_LABEL4 = 1004 '* %IDC_LABEL5 = 1005 '* %IDC_LABEL6 = 1006 '* %IDC_LABEL7 = 1007 %IDC_month_tb = 1091 %IDC_GO_BN = 1092 %IDC_MONTH_LAB = 1093 %IDC_YEAR_LAB = 1094 #PBFORMS END CONSTANTS '------------------------------------------------------------------------------ TYPE daycontrol hW AS LONG ' window handle r AS rect ' rect structure for client area of window Ctl AS LONG ' control number SubClassProc AS DWORD ' current subclassproc OldSubClassProc AS DWORD ' previous subclassproc ClickFn AS DWORD ' codeptr to function to call when single click detectedend type hD AS DWORD ' dialog handle colour AS DWORD ' background colour of control ztext AS ASCIZ * 3 ' text value (1..31) END TYPE GLOBAL g_calday() AS daycontrol DECLARE FUNCTION OnClickFnPrototype ( n AS LONG) AS LONG '------------------------------------------------------------------------------ ' ** Declarations ** '------------------------------------------------------------------------------ DECLARE CALLBACK FUNCTION ShowcaldlgProc() DECLARE FUNCTION Showcaldlg(BYVAL hParent AS DWORD) AS LONG #PBFORMS DECLARATIONS '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' subclassed stuff '---------------------------------------------------------------------------- ' this function takes care of messages for the subclassed control ' FUNCTION SubClassStaticProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS LONG, _ BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG STATIC hDC, i AS LONG ' ' work out for which image we were called ' FOR i = 1 TO UBOUND(g_calday) ' IF g_calday(i).hW = hWnd THEN ' EXIT FOR ' END IF ' NEXT ' hDC = GetDC(hWnd) SELECT CASE wMsg CASE %WM_PAINT FOR i = 1 TO UBOUND(g_calday) IF g_calday(i).hW = hWnd THEN EXIT FOR END IF NEXT ' don't need a DC, BeginPaint does it! hDC = GetDC(hWnd) CALL PaintW(i, 0) FUNCTION = 0 EXIT FUNCTION CASE %WM_ERASEBKGND FOR i = 1 TO UBOUND(g_calday) IF g_calday(i).hW = hWnd THEN EXIT FOR END IF NEXT CALL paintW(i, hDC) releasedc hWnd, hDC FUNCTION = 1 EXIT FUNCTION CASE %WM_LBUTTONDOWN FOR i = 1 TO UBOUND(g_calday) IF g_calday(i).hW = hWnd THEN EXIT FOR END IF NEXT IF g_calday(i).ClickFn <> %NULL THEN ' call click fn only if one was set up CALL DWORD g_calday(i).Clickfn USING OnClickFnPrototype (i) END IF FUNCTION = 1 EXIT FUNCTION 'A Label control by default returns HTTRANSPARENT when it receives the WM_NCHITTEST 'message. As a result, mouse messages are passed directly to the window underneath the 'label control. To receive mouse messages for the label control, add the following 'code to the subclass procedure for the label control. ~ DOMINIC MITCHELL CASE %WM_NCHITTEST FUNCTION = %HTCLIENT EXIT FUNCTION END SELECT ' Pass the message on to the original window procedure... the DDT engine! FUNCTION = CallWindowProc(g_calday(i).OldSubClassProc, hWnd, wMsg, wParam, lParam) END FUNCTION '----------------------------------------------------------------------------- ' 1st param is the subscript to g_imgr table for current static image control ' 2nd is DC is called for a WM_ERASEBKGND message, zero for a WM_PAINT message ' SUB PaintW(I AS LONG, hDCin AS LONG) LOCAL ps AS PAINTSTRUCT 'LOCAL r AS RECT LOCAL hdc, hG AS DWORD LOCAL result, tx, ty, framex, framey, ofsx, ofsy AS LONG LOCAL wide, high AS SINGLE LOCAL tlb AS LOGBRUSH ' specifies information used to create background LOCAL hbrush AS DWORD LOCAL oldBk AS INTEGER IF hDCin = 0 THEN hDC = BeginPaint(g_calday(I).hW, ps) ELSE hDC = hDCin END IF tlb.lbStyle = %BS_SOLID tlb.lbColor = g_calday(I).colour tlb.lbHatch = 0 hBrush = CreateBrushIndirect(tlb) FillRect hdc, g_calday(I).r, hBrush DeleteObject hBrush oldBk = SetBkMode(hdc, %TRANSPARENT) DrawTextEx hdc,g_calday(I).ztext, LEN(g_calday(I).ztext), g_calday(I).r, %DT_SINGLELINE OR %DT_LEFT OR %DT_VCENTER OR %DT_END_ELLIPSIS, BYVAL %NULL SetBkMode hdc, OldBk ' if DC was passed in, let caller release it! IF hDCin = 0 THEN EndPaint(g_calday(I).hW, ps) END SUB '------------------------------------------------------------------------------ ' ** Main Application Entry Point ** '------------------------------------------------------------------------------ FUNCTION PBMAIN() Showcaldlg %HWND_DESKTOP END FUNCTION '------------------------------------------------------------------------------ FUNCTION dayof1st ( year AS LONG, month AS LONG) AS LONG LOCAL st AS systemtime, ft AS filetime ' find which day of the week starts June 2006: st.wMonth = month st.wYear = year st.wDay = 1 SystemTimeToFileTime st, ft FileTimeToSystemTime ft, st FUNCTION = St.wDayofWeek '( 0=Sun, 1 = Mon,...) END FUNCTION '--------------------------------------------------------- FUNCTION daysinmonth ( year AS LONG, month AS LONG) AS LONG SELECT CASE month CASE 9,4,6,11 FUNCTION = 30 CASE 2 FUNCTION = 28 IF year MOD 1000 = 0 THEN FUNCTION = 28 ELSE IF year\4 = year/4 THEN FUNCTION = 29 END IF CASE ELSE FUNCTION = 31 END SELECT END FUNCTION '----------------------------------------------------------------------------- FUNCTION month_number ( s AS STRING) AS LONG LOCAL m AS STRING LOCAL p AS LONG LOCAL month AS LONG m = ".JAN.FEB.MAR.APR.MAY.JUN.JUL.AUG.SEP.OCT.NOV.DEC." p = INSTR(m, "." + UCASE$(LEFT$(s,3)) + ".") IF p = 0 THEN EXIT FUNCTION month = (p \ 4)+ 1 FUNCTION = month END FUNCTION '------------------------------------------------------------------- ' declared to conform with OnClickFnPrototype FUNCTION Beepfn ( i AS LONG) AS LONG BEEP END FUNCTION '------------------------------------------------------------------- ' declared to conform with OnClickFnPrototype FUNCTION toggledaycolour ( i AS LONG ) AS LONG IF TRIM$(g_calday(i).ztext) = "" THEN EXIT FUNCTION IF g_calday(i).colour = %LTGRAY THEN g_calday(i).colour = RGB(147, 201, 227) ELSE g_calday(i).colour = %LTGRAY END IF invalidaterect(g_calday(i).hW,g_calday(i).r,%false) END FUNCTION '------------------------------------------------------------------------------ ' ** CallBacks ** '------------------------------------------------------------------------------ CALLBACK FUNCTION ShowcaldlgProc() STATIC i, j, start AS LONG STATIC year AS LONG STATIC month AS LONG STATIC s AS STRING LOCAL lastday, offset1st AS LONG SELECT CASE AS LONG CBMSG CASE %WM_INITDIALOG ' Initialization handler CONTROL SET TEXT CBHNDL, %idc_month_tb , "JUNE 2006" month = 6 year = 2006 offset1st = dayof1st(year, month) DIM g_calday(42) FOR i = 1008 TO 1049 j = i - 1007 g_calday(j).Ctl = i CONTROL HANDLE CBHNDL, i TO g_calday(j).hW getClientRect (g_calday(j).hW, g_calday(j).r) g_calday(j).ClickFn = CODEPTR(BeepFn) g_calday(j).hD = CBHNDL g_calday(j).colour = RGB(147, 201, 227) ' clear day numbers g_calday(j).ztext = "" g_calday(j).OldSubClassProc = SetWindowLong(g_calday(j).hW, %GWL_WNDPROC, CODEPTR(SubClassStaticProc)) NEXT CASE %WM_NCACTIVATE STATIC hWndSaveFocus AS DWORD IF ISFALSE CBWPARAM THEN ' Save control focus hWndSaveFocus = GetFocus() ELSEIF hWndSaveFocus THEN ' Restore control focus SetFocus(hWndSaveFocus) hWndSaveFocus = 0 END IF CASE %WM_LBUTTONDOWN SendMessage CBHNDL, %WM_NCLBUTTONDOWN, %HTCAPTION, BYVAL %NULL ' force drag CASE %WM_COMMAND ' Process control notifications SELECT CASE AS LONG CBCTL CASE %IDC_go_bn ' extract month & year from text box CONTROL GET TEXT CBHNDL, %idc_month_tb TO s month = month_number(PARSE$(s," ",1)) IF month = 0 THEN BEEP year = 2006: month = 6 EXIT SELECT END IF year = VAL(PARSE$(s," ",2)) IF year < 1900 THEN BEEP year = 2006: month = 6 EXIT SELECT END IF offset1st = dayof1st(year, month) FOR i = 1008 TO 1049 j = i - 1007 g_calday(j).ztext = "" ' set up text to equal string of day number IF (j > offset1st) AND ((j - offset1st) <= daysinmonth(year, month)) THEN g_calday(j).ztext = TRIM$(STR$(j - offset1st )) g_calday(j).ClickFn = CODEPTR(ToggleDayColour) END IF NEXT DIALOG REDRAW CBHNDL END SELECT CASE %wm_destroy FOR i = 1008 TO 1049 j = i - 1007 SetWindowLong g_calday(j).hW, %GWL_WNDPROC, g_calday(j).OldSubClassProc NEXT END SELECT END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Dialogs ** '------------------------------------------------------------------------------ FUNCTION Showcaldlg(BYVAL hParent AS DWORD) AS LONG LOCAL lRslt AS LONG LOCAL col, i, row, x, y AS LONG #PBFORMS BEGIN DIALOG %IDD_caldlg->-> LOCAL hDlg AS DWORD DIALOG NEW hParent, "", 71, 71, 140,80,%WS_POPUP OR %WS_THICKFRAME OR _ %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _ %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_TOOLWINDOW OR _ %WS_EX_TOPMOST OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _ %WS_EX_RIGHTSCROLLBAR, TO hDlg CONTROL ADD LABEL, hDlg, %IDC_LABEL1, "Sun", 0, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL1, -1, RGB(79, 169, 217) CONTROL ADD LABEL, hDlg, %IDC_LABEL2, "Mon", 20, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL2, -1, RGB(79, 169, 217) CONTROL ADD LABEL, hDlg, %IDC_LABEL3, "Tues", 40, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL3, -1, RGB(79, 169, 217) CONTROL ADD LABEL, hDlg, %IDC_LABEL4, "Wed", 60, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL4, -1, RGB(79, 169, 217) CONTROL ADD LABEL, hDlg, %IDC_LABEL5, "Thu", 80, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL5, -1, RGB(79, 169, 217) CONTROL ADD LABEL, hDlg, %IDC_LABEL6, "Fri", 100, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL6, -1, RGB(79, 169, 217) CONTROL ADD LABEL, hDlg, %IDC_LABEL7, "Sat", 120, 10, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING CONTROL SET COLOR hDlg, %IDC_LABEL7, -1, RGB(79, 169, 217) CONTROL ADD TEXTBOX, hDlg, %IDC_month_tb, "", 0, 0, 54, 10, %WS_CHILD OR _ %WS_VISIBLE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %ES_UPPERCASE CONTROL SET COLOR hDlg, %IDC_month_tb, -1, RGB(147, 201, 227) CONTROL ADD BUTTON, hDlg, %IDC_go_bn, ">", 55, 0,10,10 #PBFORMS END DIALOG FOR i = 1008 TO 1049 col = (i - 1001) MOD 7 : x = col * 20 row = (i-1001) \ 7: y = 10 + (row * 10) CONTROL ADD LABEL, hDlg, i, "", x, y, 20, 10, %WS_CHILD OR _ %WS_VISIBLE OR %SS_CENTER OR %SS_CENTERIMAGE, %WS_EX_LEFT OR _ %WS_EX_LTRREADING OR %ws_ex_staticedge CONTROL SET COLOR hDlg, i, -1, RGB(147, 201, 227) NEXT DIALOG SHOW MODAL hDlg, CALL ShowcaldlgProc TO lRslt #PBFORMS BEGIN CLEANUP %IDD_caldlg #PBFORMS END CLEANUP FUNCTION = lRslt END FUNCTION
[This message has been edited by Chris Holbrook (edited June 13, 2006).]
Comment