Subject: Useful 4gl Function
Date: 10 Feb 94 21:46:41 GMT
Newsgroups: comp.databases.informix

here is a very userful Informix function that all users will love.  It pops up
a calendar with the starting date of the calendar being the date the programmer 
calls it with.  The user can then select a valid date, or go back a month
or forward a month or to any date. 

Have Fun

Stuart Litel
[email-masked]
9 years of Informix programming and I feel like I am stuck in a ring menu with no Exit

main
	define cc		smallint
	define dte		date

	defer interrupt
	options input wrap

	call calx(TODAY) returning cc, dte
	if (cc = TRUE) then
		display "User selected: ", dte 
	else
		display "User cancelled"
	end if
end main
#
#############CUT HERE FOR CALX.4gl###########################################
# Modified by Stuart Litel (Internet: [email-masked])
#
# This program lets you pop up a calendar with a default date
# The user then may press Function keys to the next month or previous month
# Or they may enter any date and the calendar will go to that month
#
# If the user presses the Accept key, the function will return TRUE and
# the date.  If they press the INTERRUPT (in this case where I wrote it 
# for it was ^C) then it will return FALSE meaning the user selected no
# date.
#
#
# The only requirement is calx.per which is at the bottom of this
# file.  This is very useful and all users who have any date entry
# love it since they now have a calendar.  It can be setup with an on-key
# statement for any date field you have to call the pop-up calendar.
#
# To test it out,simply cut out the form below and call it calx.per. 
#
# Then compile the form and compile this program "as is" and run it.
#
# To build into your code, simply remove the main above and and include it
# in your code.
#
#############################################################################
#############################################################################
# Routine    :	calx
#
# Purpose    :	setup and control for calendar display
#
# Arguments  :	sdte		- date to start display with
#
# Returns    :	cc		- TRUE  if user selected, FALSE if they did not
#				sdte	- a selected date (IF CC = TRUE)
#
#############################################################################

function calx(sdte) 
	define sdte	date
	define cc		smallint
	define in_date 	date
	define old_date	date

	if (sdte is not NULL) then
		let in_date = sdte
	else
		let in_date = today
	end if

	open window calx at 6,15 with form "calx" #14 rows, 25 columns
		attribute (border, comment line 1, form line 1)

	display "^N=Next Mon, ^P-Prev. Mon, ^T=Today" at 13,2
	display "^C=Interrupt, Esc=Accept" at 14,2
	call calendar(in_date,2,1,1) 
	let old_date = in_date

	let cc = TRUE
	let int_flag = FALSE
	input in_date without defaults from formonly.in_date
		on key (control-N) 	#next month
			call get_mon("N",old_date) returning in_date
			call calendar(in_date,2,1,1) 
			let old_date = in_date
			display in_date to formonly.in_date
		on key (Control-P) 	#last month
			call get_mon("B",old_date) returning in_date
			call calendar(in_date,2,1,1) 
			let old_date = in_date
			display in_date to formonly.in_date

		on key (Control-T) 
			let in_date = today
			call calendar(in_date,2,1,1) 
			let old_date = in_date
			display in_date to formonly.in_date

		before field in_date
			display in_date to formonly.in_date

		after field in_date
			if (in_date is not NULL) then
				call calendar(in_date,2,1,1) 
				let old_date = in_date
			end if

	end input
	if (int_flag = TRUE) then
		let cc = FALSE
		let int_flag = FALSE
	end if

	close window calx
	return cc, old_date
end function

#PB
#-----------------------------------------------------------------------------
# Routine    :	calendar
#
# Purpose    :	calculates and displays actual calendar
#
# Arguments  :	in_date    	date to start display at
#				v_pos		Vertical position of top of calendar
#				h_offset	horizontal start of display
#				actual_flag	smallint
#
# Returns    :	Nothing.
#-----------------------------------------------------------------------------
function calendar(in_date,v_pos,h_offset,actual_flag) 

	define temp_date	date		#First date for the month {05/01/1989}
	define in_date     	date 
	define in_month 	smallint	#Month passed in through in_date
	define in_year  	smallint 	#Year passed in through in_date
	define in_day   	smallint 	#Day of mon passed in through in_date{1-31}
	define in_wkday		smallint 	#Weekday in numerical form {0 = Sunday}
	define first_wkday	smallint 	#Weekday of the first day of the month
	define v_pos		smallint 	#Vertical position of top of calendar
	define h_pos      	smallint 	#+ h_offset = screen position of next date
									#to be displayed
	define h_offset		smallint
	define actual_flag	smallint
	define day_count	smallint	#Position within wk of the date to display
	define max_days    	smallint	#Number of days in this month
	define in_mon_word 	char(20)
	define in_day_word 	char(20) 	#English word for the day of the week
	define v_sp_pos		smallint
	define x			smallint

	# Break the date up into its parts
	let in_wkday = weekday(in_date) 
	let in_month = month(in_date) 
	let in_year = year(in_date) 
	let in_day = day(in_date) 

	# create the first day of the month to get the first wkday of the month
	let temp_date = mdy(in_month,1,in_year) 
	let first_wkday = weekday(temp_date) 

	# get the number of days in the month
	let max_days = maximum_days(in_month,in_year) 
	# get the English abbreviation of the month and day
	let in_mon_word = month_word(in_month) 
	let in_day_word = day_word(in_wkday) 

	# Display the verbiage at the top of the calendar
	for x = v_pos to v_pos + 7
		display "" at x,1
	end for

	#display month and year we are in
	display "   ",in_mon_word clipped,", ",in_year at v_pos,h_offset

	#update the vertical position
	let v_pos = v_pos + 1

	#Show the Saturday through Sunday bar at the top of the calendar
	display "  S  M  T  W  T  F  S " at v_pos,h_offset attribute(reverse) 

	#calculate the horizontal position on the screen for the 1st day of month
	let h_pos = h_offset+((first_wkday)*3) 

	# update the vertical position
	let v_pos = v_pos + 1
	# clear the line first
	display "" at v_pos,h_offset

	# place days on the calendar
	for day_count = 1 to max_days
		if (day_count = in_day) 
			and (actual_flag = 1) then # high-light the passed in date

			display day_count using "###" at v_pos,h_pos attribute (REVERSE)

		else # display the dates in normal video
			display day_count using "###" at v_pos,h_pos
		end if

		if (h_pos < h_offset+18) then # haven't reached the right side 
			let h_pos = h_pos + 3
		else # move to the next week position
			let h_pos = h_offset
			let v_pos = v_pos + 1
			# clear the line first
			display "" at v_pos,h_offset
		end if
	end for
end function
#-----------------------------------------------------------------------------
# Routine    :	day_word
#
# Purpose    :	figure out what day of the week it is
#
# Arguments  :	in_wkday		(0 for Sunday .... 6 for Saturday)
#
# Returns    :	dow			Character day of the week (Sunday, Monday....)
#-----------------------------------------------------------------------------

function day_word(in_wkday) 
	define in_wkday smallint
	define dow	char(9)

	case
		when in_wkday = 0
			let dow = "Sunday" 
		when in_wkday = 1
			let dow = "Monday" 
		when in_wkday = 2
			let dow = "Tuesday" 
		when in_wkday = 3
			let dow = "Wednesday" 
		when in_wkday = 4
			let dow = "Thursday" 
		when in_wkday = 5
			let dow = "Friday" 
		when in_wkday = 6
			let dow = "Saturday" 
	end case
	return dow
end function
#PB
#-----------------------------------------------------------------------------
# Routine    :	month_word
#
# Purpose    :	figure out what month it is
#
# Arguments  :	in_month		(1 for January ....  12 for December)
#
# Returns    :	mon			Character month (January, Febuary, etc...)
#-----------------------------------------------------------------------------
function month_word(in_month) 
	define in_month smallint
	define mon		char(11)

	case
		when in_month = 1
			let mon = "January" 
		when in_month = 2
			let mon = "February" 
		when in_month = 3
			let mon = "March" 
		when in_month = 4
			let mon = "April" 
		when in_month = 5
			let mon = "May" 
		when in_month = 6
			let mon = "June" 
		when in_month = 7
			let mon = "July" 
		when in_month = 8
			let mon = "August" 
		when in_month = 9
			let mon = "September" 
		when in_month = 10
			let mon = "October" 
		when in_month = 11
			let mon = "November" 
		when in_month = 12
			let mon = "December" 
	end case
	return mon
end function

#-----------------------------------------------------------------------------
# Routine    :	maximum_days
#
# Purpose    :	To figure how many days are in the month
#
# Arguments  :	in_month		1 thru 12 fro month we want
#				in_year			what year are we in???
#
# Returns    :	dy				the number of days in the month
#-----------------------------------------------------------------------------
function maximum_days(in_month,in_year) 
	define in_month	smallint
	define in_year 	smallint
	define dy		smallint

	case
		when (in_month = 1 or in_month = 3 or in_month = 5 or in_month = 7 or
			in_month = 8 or in_month = 10 or in_month = 12)

			let dy = 31

		when in_month = 4 or in_month = 6 or in_month = 9 or in_month = 11
			let dy = 30

		otherwise # this is February so check for a leap year

			if (in_year mod 4 = 0 and in_year != 2000 ) then # this is a leap year
				let dy = 29
			else
				let dy = 28
			end if
	end case
	return dy
end function

#-----------------------------------------------------------------------------
# Routine    :	get_mon
#
# Purpose    :	to get next or previous month
#
# Arguments  :	opt					#'F'orwards or 'B'ackwards
#				dte					the date we want to find the month for
#
# Returns    :	dte				start of month
#-----------------------------------------------------------------------------
function get_mon(opt,dte)
define opt		char(1)			#'F'orwards or 'B'ackwards
define dte		date
define str		char(10)
define mon		smallint
define yr		smallint

	let str = dte using "MM/DD/YYYY"

	let mon = str[1,2]
	let yr = str[7,10]

	if (opt = "B") then
		let mon = mon - 1
		if (mon  < 1) then
			let mon = 12
			let yr = yr - 1
		end if
	else
		let mon = mon + 1
		if (mon > 12) then
			let mon = 1
			let yr = yr + 1
		end if
	end if
	let str = mon using "##", "/01/",yr using "####"
	let dte = str
	return dte
end function

####CUT HERE for calx.per ###########################
database formonly
screen 
{

         Date            [f000      ]

}
end
attributes
f000 = formonly.in_date, reverse;
end
######END OF FORM calx.per #####################################