FOR EACH loControl IN laSelected >>> amouseobj( laM, 1 ) >>> loControl.Left = laM[3] && m.loControl.Left + m.lnHOffset >>> loControl.Top = laM[4] &&m.loControl.Top + m.lnVOffset >>>ENDFOR>>>
LPARAMETERS tlCopyHorizontally AS Boolean, tnSpacing AS Number >>>>#IF .F. >>>>PARAMETERS: >>>> tlCopyHorizontally (O) - Indicates whether the new controls should be >>>> copied and aligned to the right of the selected >>>> controls. If omitted, defaults to .F., the >>>> controls will be copied below the selected >>>> controls. >>>> tnSpacing (O) - Indicates how many pixels to leave between the >>>> selected group of controls, and the new controls. >>>> IF omitted, defaults to 5. >>>> >>>>USAGE: >>>> ON KEY LABEL CTRL+K DO oxCopyCtrl WITH .F., 10 >>>> >>>>NOTES: >>>> We experience a refresh problem with this routine. Although the >>>> controls were being copied and repositioned correctly, they often >>>> appeared to be cut off (so that only the top or left edge of the group >>>> of controls could be seen). Clicking in the form seemed to correct this, >>>> but it would be better if the display could be corrected programmatically. >>>>#ENDIF >>>> >>>>*-- When controls are copied and pasted without using the mouse, >>>>*-- the default position for the new controls is 8 pixels below >>>>*-- and 8 pixels to the right of the position of the selected >>>>*-- controls. >>>>#DEFINE DEFAULT_LEFT_OFFSET 8 >>>>#DEFINE DEFAULT_TOP_OFFSET 8 >>>> >>>>LOCAL laSelected[1], ; >>>> loControl AS Container, ; >>>> lnLeft, ; >>>> lnRight, ; >>>> lnTop, ; >>>> lnBottom, ; >>>> lnHOffset, ; >>>> lnVOffset >>>> >>>>*-- Check if the user wants to copy the controls horizontally, rather >>>>*-- than vertically. >>>>tlCopyHorizontally = ( VARTYPE( m.tlCopyHorizontally ) = "L" ; >>>> AND m.tlCopyHorizontally ) >>>> >>>>*-- If a numeric value for spacing was passed, use it, otherwise we'll >>>>*-- default to 5 pixels. >>>>tnSpacing = IIF( VARTYPE( m.tnSpacing ) = "N", INT( m.tnSpacing ), 5 ) >>>> >>>>*-- Initialize the position variables so that the first control that's >>>>*-- processed will update these variables with it's values. >>>>lnLeft = 1000000 >>>>lnRight = -1000000 >>>>lnTop = 1000000 >>>>lnBottom = -1000000 >>>> >>>>*-- Populate an array with object references for all selected controls. >>>>IF ASELOBJ( laSelected ) = 0 >>>> *-- Nothing was selected, so there's nothing to do. >>>> RETURN >>>>ENDIF >>>> >>>>*-- Determine the outer boundaries for the group of controls. >>>>FOR EACH loControl IN laSelected >>>> lnLeft = MIN( m.lnLeft, m.loControl.Left ) >>>> lnRight = MAX( m.lnRight, m.loControl.Left + m.loControl.Width ) >>>> lnTop = MIN( m.lnTop, m.loControl.Top ) >>>> lnBottom = MAX( m.lnBottom, m.loControl.Top + m.loControl.Height ) >>>>ENDFOR >>>> >>>>*-- Clear this variable, just to make sure we don't leave behind any >>>>*-- dangling object references. >>>>loControl = .NULL. >>>> >>>>IF m.tlCopyHorizontally >>>> *-- The controls are to copied horizontally (to the right), so the >>>> *-- new controls need to be moved to the right by the total width of >>>> *-- the selected *group* of controls, minus the distance to the right >>>> *-- that the new controls will have already moved, plus the spacing >>>> *-- that was specified. >>>> lnHOffset = m.lnRight - m.lnLeft - DEFAULT_LEFT_OFFSET + m.tnSpacing >>>> *-- Move the controls back up by the amount that they will have been >>>> *-- moved down, so that they align vertically with the original >>>> *-- controls. >>>> lnVOffset = -1 * DEFAULT_TOP_OFFSET >>>>ELSE >>>> *-- Move the controls back to the left by the amount that they will >>>> *-- have been moved to the right, so that they align horizontally with >>>> *-- the original controls. >>>> lnHOffset = -1 * DEFAULT_LEFT_OFFSET >>>> *-- The controls are to copied vertically (down), so the new controls >>>> *-- need to be moved down by the total height of the selected *group* >>>> *-- of controls, minus the distance down that the new controls will >>>> *-- have already moved, plus the spacing that was specified. >>>> lnVOffset = m.lnBottom - m.lnTop - DEFAULT_TOP_OFFSET + m.tnSpacing >>>>ENDIF >>>> >>>> >>>> >>>>*-- Flush the keyboard buffer, and copy the selected controls. >>>>KEYBOARD '{MOUSE}' PLAIN CLEAR >>>>SYS( 1500, "_MED_COPY", "_MEDIT" ) >>>> >>>>*-- We seem to need a pause here while the clipboard is being populated. >>>>*-- A half-second worked well for me, but your results may vary. >>>>WAIT WINDOW "" NOCLEAR TIMEOUT .5 >>>> >>>>*-- Flush the keyboard buffer again, and paste the copied controls. >>>>KEYBOARD '{MOUSE}' PLAIN CLEAR >>>>SYS( 1500, "_MED_PASTE", "_MEDIT" ) >>>> >>>>*-- A pause after the paste also seems to be needed. >>>>WAIT WINDOW "" NOCLEAR TIMEOUT .5 >>>> >>>>*-- The controls that were just pasted will now be the selected controls. >>>>*-- Get the object references for them into an array so that we can scan >>>>*-- through and adjust the positions of the controls. >>>>ASELOBJ( laSelected ) >>>>FOR EACH loControl IN laSelected >>>> loControl.Left = m.loControl.Left + m.lnHOffset >>>> loControl.Top = m.loControl.Top + m.lnVOffset >>>>ENDFOR >>>> >>>>*-- Mike Yearwood - Feb 21, 2006 >>>>*-- Setting focus to anything on the form/class designer >>>>*-- seems to remove the refreshing problems. >>>>*!* m.loControl.Parent.SetFocus() >>>> >>>>*-- Mike Yearwood - March 12, 2006 >>>>*-- Better yet, how about setting focus to the first >>>>*-- control in the new set. >>>>FOR EACH m.loControl IN laSelected >>>> IF PEMSTATUS(m.loControl,"SETFOCUS",5) >>>> m.loControl.SetFocus() >>>> EXIT >>>> ENDIF >>>>ENDFOR EACH m.loControl >>>> >>>>*-- Clear this variable, just to make sure we don't leave behind any >>>>*-- dangling object references. >>>>loControl = .NULL.