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.