home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / devtools / dataflex / calendar.pkg < prev    next >
Encoding:
Text File  |  1993-05-19  |  21.7 KB  |  671 lines

  1. //
  2. // Calendar.Pkg
  3. // November 26, 1991
  4. // Theo van Dongeren
  5. //
  6. // Modeless prompt package for date values
  7. //
  8.  
  9. #CHKSUB 1 1 // Verify the UI subsystem.
  10.  
  11. use ui
  12. use sysbutn
  13.  
  14. /calendar
  15. ┌─[_]─────────────────────┐
  16. │_________________________│
  17. │Wk│Su Mo Tu We Th Fr Sa  │
  18. │_.│_. _. _. _. _. _. _.  │
  19. │_.│_. _. _. _. _. _. _.  │
  20. │_.│_. _. _. _. _. _. _.  │
  21. │_.│_. _. _. _. _. _. _.  │
  22. │_.│_. _. _. _. _. _. _.  │
  23. │_.│_. _. _. _. _. _. _.  │
  24. │  <_______>   <_______>  │
  25. └─────────────────────────┘
  26. /calendar_system_pull_down
  27. ┌────────────────┐
  28. │ ______________ │
  29. │ ______________ │
  30. └────────────────┘
  31. /*
  32.  
  33. #IFDEF P_ACTION_BAR
  34. #ELSE
  35.     #REPLACE P_ACTION_BAR |CI3
  36. #ENDIF
  37.  
  38. class system_pull_down is a menu
  39.     procedure construct_object integer image
  40.         forward send construct_object image
  41.  
  42.         set popup_state to true
  43.         set exit_msg to exit
  44.         set class_palette of desktop to u_system_pull_down p_action_bar
  45.         set inverse_state to true
  46.  
  47.         on_key kcancel send deactivate private
  48.     end_procedure
  49.  
  50.     procedure move_parent
  51.         send deactivate
  52.         send move_calendar
  53.     end_procedure
  54.  
  55.     procedure mouse_click 
  56.         send go_away
  57.     end_procedure
  58. end_class
  59.  
  60. class calendar_scrollb is a scrollb
  61.     procedure set arrows integer up_ar integer dn_ar
  62.         // always force scrollbar arrows on
  63.         forward set arrows true true
  64.     end_procedure
  65. end_class
  66.  
  67. register_object monthsize
  68.  
  69. // this class handles the calendar body (the day numbers)
  70. class calendar_body is a list
  71.     procedure construct_object integer image
  72.         forward send construct_object image
  73.  
  74.         object scroll_bar is a calendar_scrollb
  75.         end_object
  76.  
  77.         set scroll_bar_offset to 1
  78.  
  79.         on_key key_alt+key_f10 send pull_down_system private
  80.  
  81.         property integer ok_item public
  82.  
  83.         item_list
  84.             repeat_item 42 times '' send move_value_out
  85.         end_item_list
  86.     end_procedure
  87.  
  88.     // check if new item is valid (non-zero)
  89.     // keep this information handy for msg_mouse_up which
  90.     // will be sent if the item selection was made by mouse
  91.     procedure set current_item integer item#
  92.         local integer invalid
  93.  
  94.         get shadow_state item item# to invalid
  95.         if (not(invalid)) begin
  96.             set ok_item to true
  97.             forward set current_item to item#
  98.         end
  99.         else set ok_item to false
  100.     end_procedure
  101.  
  102.     // check if mouse selection is valid
  103.     // uses information set by set_current_item
  104.     procedure mouse_up integer win# integer char
  105.         local integer valid
  106.  
  107.         get ok_item to valid
  108.         if valid forward send mouse_up win# char
  109.     end_procedure
  110.  
  111.     // augmented to update properties needed for date calculations
  112.     procedure item_change integer from# integer to# returns integer
  113.         // update properties
  114.         delegate send newdate (to# - from#)
  115.         // go to new item
  116.         procedure_return to#
  117.     end_procedure
  118.  
  119.     // initializes the calendar body display and the properties needed
  120.     // for date calculations
  121.     procedure init_body integer thismonth
  122.         local integer index day offset prevmonth
  123.         local date startdate
  124.  
  125.         // turn off real-time display update
  126.         set dynamic_update_state to false
  127.  
  128.         // get work values
  129.         delegate get original_date to startdate
  130.         delegate get work_day to day
  131.  
  132.         // calculate weekday of day one of this month
  133.         // NB. startdate has 4-digit year
  134.         move (mod((startdate - day - 1),7)) to offset
  135.  
  136.         get work_month to prevmonth
  137.         move (mod((prevmonth + 10),12) + 1) to prevmonth
  138.         get integer_value of (monthsize(parent(current_object))) item prevmonth ;
  139.             to prevmonth
  140.  
  141.         // fill in calendar body display
  142.         for index from 0 to 41
  143.             if (index < offset) begin
  144.                 set value item index to (index - offset + prevmonth + 1)
  145.                 set shadow_state item index to true
  146.             end
  147.             else if (index >= (offset + thismonth)) begin
  148.                 set value item index to (index - offset - thismonth + 1)
  149.                 set shadow_state item index to true
  150.             end
  151.             else begin
  152.                 set value item index to (index - offset + 1)
  153.                 set shadow_state item index to false
  154.             end
  155.         loop
  156.  
  157.         // protect original_date, work_date and work_day, since set_current_item
  158.         // will send msg_item_change, which changes these properties.
  159.         delegate get work_date to index
  160.  
  161.         // preset current_item
  162.         set current_item to (day + offset - 1)
  163.  
  164.         // restore work properties
  165.         delegate set original_date to startdate
  166.         delegate set work_date to index
  167.         delegate set work_day to day
  168.  
  169.         // display new calendar body
  170.         set dynamic_update_state to true
  171.     end_procedure
  172.  
  173.     // override scroll messages sent by scrollbar
  174.     procedure scroll integer direction integer distance
  175.         if direction send next_month
  176.         else send prev_month
  177.     end_procedure
  178. end_class
  179.  
  180. // this class handles the calendar popup
  181. class calendar_popup is a client
  182.     procedure construct_object integer dummy
  183.         local integer c1 c2
  184.  
  185.         // force usage of the built-in image
  186.         forward send construct_object calendar.n
  187.  
  188.         property date original_date public          // the 'real' date
  189.         property date work_date public              // previous minus centuries
  190.         property integer work_year public
  191.         property integer work_month public
  192.         property integer work_day public
  193.         property integer work_adjust public         // # of centuries
  194.         property integer invoking_object public     // object that called us
  195.         property integer doing_exit public (false)  // flag to prevent recursion
  196.         property string monthnames public ;
  197.             'January  February March    April    May      June     July     August   SeptemberOctober  November December '
  198.  
  199.  
  200.         // default state
  201.         set popup_state to true
  202.         set scope_state to true
  203.  
  204.         // accelerator key definitions
  205.         on_key kcancel send go_away
  206.         on_key kclose_panel send go_away
  207.         on_key kfind_previous send prev_year
  208.         on_key kfind_next send next_year
  209.         on_key kscroll_back send prev_month
  210.         on_key kscroll_forward send next_month
  211.  
  212.         sub_page sysbutton from calendar 1
  213.         sub_page title_box from calendar 2
  214.         sub_page weeks from calendar vertical 3 6
  215.         sub_page cal_body from calendar rectangular 4 7 6
  216.         sub_page button from calendar horizontal 51 2
  217.  
  218.         // month sizes; note that size of february is missing.
  219.         // this value is filled in as we go
  220.         object monthsize is an array
  221.             set array_value item 1  to 31
  222.             set array_value item 3  to 31
  223.             set array_value item 4  to 30
  224.             set array_value item 5  to 31
  225.             set array_value item 6  to 30
  226.             set array_value item 7  to 31
  227.             set array_value item 8  to 31
  228.             set array_value item 9  to 30
  229.             set array_value item 10 to 31
  230.             set array_value item 11 to 30
  231.             set array_value item 12 to 31
  232.         end_object
  233.  
  234.         // system button
  235.         object sysbutton is a system_button
  236.             item_list
  237.                 on_item '≡' send pull_down_system
  238.             end_item_list
  239.         end_object
  240.  
  241.         // system menu
  242.         object calendar_system_pull_down is a system_pull_down
  243.             set location to 1 0 relative
  244.  
  245.             item_list
  246.                 on_item 'Move...       ' send move_parent
  247.                 on_item 'Close  Ctrl+F4' send go_away
  248.             end_item_list
  249.         end_object
  250.  
  251.         // calendar title
  252.         object title_box is a title
  253.             set center_state item 0 to true
  254.             set value item 0 to ''
  255.         end_object
  256.  
  257.         // weeknumbers
  258.         object weeks is a title
  259.             set value item 0 to ''
  260.             set value item 1 to ''
  261.             set value item 2 to ''
  262.             set value item 3 to ''
  263.             set value item 4 to ''
  264.             set value item 5 to ''
  265.             set shadow_state item 0 to true
  266.             set shadow_state item 1 to true
  267.             set shadow_state item 2 to true
  268.             set shadow_state item 3 to true
  269.             set shadow_state item 4 to true
  270.             set shadow_state item 5 to true
  271.         end_object
  272.  
  273.         // calendar body (day numbers plus scrollbar)
  274.         object body is a calendar_body cal_body
  275.         end_object
  276.  
  277.         // buttons for going to previous and next year
  278.         object button is a button
  279.             set focus_mode to pointer_only
  280.             item_list
  281.                 on_item '' send prev_year
  282.                 set center_state to true
  283.                 on_item '' send next_year
  284.                 set center_state to true
  285.             end_item_list
  286.         end_object
  287.     end_procedure
  288.  
  289.     procedure pull_down_system
  290.         send popup to (calendar_system_pull_down(current_object))
  291.     end_procedure
  292.  
  293.     // we need to do this; don't just deactivate
  294.     procedure go_away
  295.         local integer new_focus
  296.  
  297.         get invoking_object to new_focus
  298.         send activate to new_focus
  299.     end_procedure
  300.  
  301.     // we need to do this; don't just deactivate
  302.     procedure exiting_scope integer new_scope returns integer
  303.         local integer new_focus retval
  304.  
  305.         if (doing_exit(current_object)) begin
  306.             forward get msg_exiting_scope new_scope to retval
  307.             procedure_return retval
  308.         end
  309.         set doing_exit to true
  310.         get scope_focus of new_scope to new_focus
  311.         send activate to new_focus
  312.         send deactivate
  313.         set doing_exit to false
  314.     end_procedure
  315.  
  316.     // returns true if supplied year is a leapyear
  317.     function leapyear integer year returns integer
  318.         function_return (mod(year,4) = 0)
  319.     end_function
  320.  
  321.     // this message will be sent by the invoking object
  322.     procedure popup
  323.         local integer obj#
  324.         local date import_date
  325.  
  326.         // add ourselves to the focus tree
  327.         forward send popup
  328.  
  329.         // find out who called us
  330.         get prior_level to obj#
  331.         set invoking_object to obj#
  332.  
  333.         // get caller's current item value
  334.         get value of obj# item current to import_date
  335.  
  336.         // initialize to today if it's zero
  337.         if import_date eq 0 sysdate import_date
  338.  
  339.         // set up starting point and prepare the display
  340.         set original_date to import_date
  341.         send init_date true
  342.     end_procedure
  343.  
  344.     // this initializes the calendar display
  345.     procedure init_date integer flag
  346.         local integer period index remainder wrk_year wrk_month jan1day
  347.         local integer namelength maxweek
  348.         local string title_text
  349.         local date wrk_date week0date jan1st
  350.  
  351.         get original_date to wrk_date
  352.  
  353.         // get # of centuries
  354.         move (wrk_date / 36525) to index
  355.  
  356.         if flag begin
  357.             // if year is less than 100 assume 2 digit year; 
  358.             // adjust by 19 centuries
  359.             if index eq 0 begin
  360.                 move 19 to index
  361.                 set work_adjust to index
  362.                 move (wrk_date + (index * 36525)) to wrk_date
  363.                 set original_date to wrk_date
  364.             end
  365.             else set work_adjust to 0
  366.         end
  367.  
  368.         // strip centuries
  369.         move (wrk_date - (index * 36525)) to wrk_date
  370.  
  371.         // keep handy
  372.         set work_date to wrk_date
  373.  
  374.         // calculate number of full 4-year periods (366 + (3 * 365) days)
  375.         move (wrk_date / 1461) to period
  376.  
  377.         // calculate # of days into current period
  378.         move (mod(wrk_date,1461)) to remainder
  379.  
  380.         // calculate current year (0 - 99)
  381.         move ((period * 4) + integer(remainder / 365.25)) to wrk_year
  382.  
  383.         // calculate Jan 1st
  384.         move (wrk_year * 365.25 + 0.75) to jan1st
  385.  
  386.         // calculate daynum of Jan 1st
  387.         move (mod(jan1st,7)) to jan1day
  388.  
  389.         // calculate date of Sunday of week 0 (week prior to week 1)
  390.         move (jan1st - jan1day) to week0date
  391.         if jan1day le 3 move (week0date - 7) to week0date
  392.  
  393.         // add centuries
  394.         move (wrk_year + (index * 100)) to wrk_year
  395.  
  396.         // keep handy
  397.         set work_year to wrk_year
  398.  
  399.         // calculate # of days into current year
  400.         // and set size of February
  401.         if (leapyear(current_object,wrk_year)) ;
  402.             set array_value of (monthsize(current_object)) item 2 to 29
  403.         else begin
  404.             set array_value of (monthsize(current_object)) item 2 to 28
  405.             move (mod((remainder - 366),365)) to remainder
  406.         end
  407.  
  408.         // make remaining # of days 1-based (was 0-based)
  409.         increment remainder
  410.  
  411.         // calculate current month
  412.         for index from 1 to 12
  413.             move index to wrk_month
  414.             get array_value of (monthsize(current_object)) item wrk_month to period
  415.             move (remainder - period) to remainder
  416.         until remainder le 0
  417.  
  418.         // keep month and day handy
  419.         set work_month to wrk_month
  420.         set work_day to (remainder + period)
  421.  
  422.         // set up title
  423.         get monthnames to title_text
  424.         move (length(title_text) / 12) to namelength
  425.         trim (mid(title_text,namelength,((wrk_month - 1) * namelength + 1))) ;
  426.             to title_text
  427.         set value of (title_box(current_object)) item 0 to (title_text + ', ' + string(wrk_year))
  428.  
  429.         // set up buttons
  430.         set value of (button(current_object)) item 0 to ('F7=' + string(wrk_year - 1))
  431.         set value of (button(current_object)) item 1 to ('F8=' + string(wrk_year + 1))
  432.  
  433.         // initialize calendar body
  434.         send init_body to (body(current_object)) period
  435.  
  436.         // initialize week column
  437.         get work_day to remainder
  438.         move ((wrk_date - remainder + 1 - week0date) / 7) to period
  439.  
  440.         // fill week column
  441.         move 52 to maxweek
  442.         set value of (weeks(current_object)) item 0 to (if(period,period,53))
  443.         for index from 1 to 5
  444.             increment period
  445.             if period eq 52 begin
  446.                 if (value(body(current_object),(index * 7))) le 21 ;
  447.                     move 53 to maxweek
  448.             end
  449.             else if period gt maxweek move 1 to period
  450.             set value of (weeks(current_object)) item index to period
  451.         loop
  452.     end_procedure
  453.  
  454.     // this gets called by calendar body due to an item change;
  455.     // updates some work properties
  456.     procedure newdate integer incr
  457.         set original_date to (original_date(current_object) + incr)
  458.         set work_date to (work_date(current_object) + incr)
  459.         set work_day to (work_day(current_object) + incr)
  460.     end_procedure
  461.  
  462.     // go to previous month
  463.     procedure prev_month
  464.         local integer prevone wrk_day
  465.         local date org_date
  466.  
  467.         get original_date to org_date
  468.  
  469.         // cannot go to prev month if this is January of year 0
  470.         if org_date lt 31 procedure_return
  471.  
  472.         // calculate previous month's number
  473.         get work_month to prevone
  474.         decrement prevone
  475.         if prevone lt 1 move 12 to prevone
  476.  
  477.         // get previous month's size and adjust date
  478.         get array_value of (monthsize(current_object)) item prevone to prevone
  479.         move (org_date - prevone) to org_date
  480.  
  481.         // find closest match if new month has fewer days than current month
  482.         get work_day to wrk_day
  483.         if wrk_day gt prevone move (org_date - wrk_day + prevone) to org_date
  484.  
  485.         // keep new date
  486.         set original_date to org_date
  487.  
  488.         // redo calendar display
  489.         send init_date false
  490.     end_procedure
  491.  
  492.     // go to next month
  493.     procedure next_month
  494.         local integer thisone nextone wrk_day
  495.         local date org_date
  496.  
  497.         get original_date to org_date
  498.  
  499.         // get this month's number
  500.         get work_month to thisone
  501.  
  502.         // get this month's size
  503.         get array_value of (monthsize(current_object)) item thisone to thisone
  504.  
  505.         // calculate next month's number
  506.         get work_month to nextone
  507.         increment nextone
  508.         if nextone gt 12 move 1 to nextone
  509.  
  510.         // get next month's size and adjust date
  511.         get array_value of (monthsize(current_object)) item nextone to nextone
  512.         move (org_date + thisone) to org_date
  513.  
  514.         // find closest match if new month has fewer days than current month
  515.         get work_day to wrk_day
  516.         if wrk_day gt nextone move (org_date - wrk_day + nextone) to org_date
  517.  
  518.         // keep new date
  519.         set original_date to org_date
  520.  
  521.         // redo calendar display
  522.         send init_date false
  523.     end_procedure
  524.  
  525.     // go to previous year
  526.     procedure prev_year
  527.         local integer adjustment year month
  528.         local date org_date
  529.  
  530.         get original_date to org_date
  531.  
  532.         // cannot go to prev year if this is year 0
  533.         if org_date lt 366 procedure_return
  534.  
  535.         get work_year to year
  536.         get work_month to month
  537.  
  538.         // check if current year is leapyear if we're in or past march
  539.         if month ge 3 move (leapyear(current_object,year)) to adjustment // set to 1 if leapyear
  540.  
  541.         // adjust date
  542.         move (org_date - 365) to org_date
  543.         decrement year
  544.  
  545.         // check if new year is leapyear if we're in or before february
  546.         if month le 2 move (leapyear(current_object,year)) to adjustment // set to 1 if leapyear
  547.  
  548.         // adjust date if necessary
  549.         move (org_date - adjustment) to org_date
  550.  
  551.         // keep date
  552.         set original_date to org_date
  553.  
  554.         // redo calendar display
  555.         send init_date false
  556.     end_procedure
  557.  
  558.     // go to next year
  559.     procedure next_year
  560.         local integer adjustment year month
  561.         local date org_date
  562.  
  563.         get original_date to org_date
  564.         get work_year to year
  565.         get work_month to month
  566.  
  567.         // check if current year is leapyear if we're in or before february
  568.         if month le 2 move (leapyear(current_object,year)) to adjustment // set to 1 if leapyear
  569.  
  570.         // adjust date
  571.         move (org_date + 365) to org_date
  572.         increment year
  573.  
  574.         // check if new year is leapyear if we're in or past march
  575.         if month ge 3 move (leapyear(current_object,year)) to adjustment // set to 1 if leapyear
  576.  
  577.         // adjust date if necessary
  578.         move (org_date + adjustment) to org_date
  579.  
  580.         // keep date
  581.         set original_date to org_date
  582.  
  583.         // redo calendar display
  584.         send init_date false
  585.     end_procedure
  586.  
  587.     // this exports a selected date to the calling object's current item
  588.     procedure move_value_out
  589.         local integer obj# adjust
  590.         local date export_date
  591.  
  592.         get original_date to export_date
  593.  
  594.         // adjust to original # of year digits if necessary
  595.         get work_adjust to adjust
  596.         if adjust move (export_date - (adjust * 36525)) to export_date
  597.  
  598.         // set calling object's current item value
  599.         get invoking_object to obj#
  600.         set value of obj# item current to export_date
  601.         set item_changed_state of obj# item current to true
  602.  
  603.         // go away
  604.         send activate to obj#
  605.     end_procedure
  606.  
  607.     // this moves the calendar popup under cursor & mouse control;
  608.     // it makes use of the rubberband inside the system button to do all
  609.     // the dirty work
  610.     procedure move_calendar
  611.         local integer complex row col
  612.         local string achar
  613.  
  614.         // set new mouse location; tie it to upper-lefthand corner of popup
  615.         get location to complex
  616.         move (hi(complex)) to row
  617.         move (low(complex)) to col
  618.         set absolute_mouse_location to row col true
  619.  
  620.         // display the rubberband
  621.         send popup to (rubberband(sysbutton(current_object)))
  622.  
  623.         // keep asking for keys
  624.         repeat
  625.             inkey achar
  626.  
  627.             // was any of the mouse keys pressed?
  628.             indicate key.mouse as flexkey eq 53
  629.  
  630.             // abort the move
  631.             [key.escape] send deactivate to (rubberband(sysbutton(current_object)))
  632.  
  633.             // check for valid key (up, down, left, right, or mouse)
  634.             [not key.escape] indicate key.ok group any [key.left key.right key.up] ;
  635.                 or any [key.down key.mouse]
  636.  
  637.             // process valid keys only
  638.             [not key.escape key.ok] begin
  639.                 // get current mouse location
  640.                 get absolute_mouse_location to complex
  641.                 move (hi(complex)) to row
  642.                 move (low(complex)) to col
  643.  
  644.                 // Note: it's important to inquire the mouse's location every time 
  645.                 // around, since dragging the rubberband may cause the mouse's
  646.                 // location to be justified when trying to drag the
  647.                 // rubberband off the screen (ie. outside of the desktop object).
  648.  
  649.                 // process arrow keys
  650.                 [key.left] decrement col
  651.                 [key.right] increment col
  652.                 [key.up] decrement row
  653.                 [key.down] increment row
  654.  
  655.                 // set new mouse location
  656.                 set absolute_mouse_location to row col true
  657.  
  658.                 // redraw rubberband at mouse location
  659.                 send drag_me to (rubberband(sysbutton(current_object)))
  660.                 // this MAY also adjust the mouse's location; see note above
  661.             end
  662.  
  663.             // moving done; drop popup at rubberband location
  664.             [key.return] send drop_me to (rubberband(sysbutton(current_object)))
  665.  
  666.         // keep going until escape or enter is pressed
  667.         [not key.escape not key.return] loop
  668.     end_procedure
  669. end_class
  670.  
  671.