********** >* custom_shape_rgn.prg >* >***** >* This is a simple program demonstrating masked region forms. This one adds >* a timer which moves some "eyes" back and forth along the bottom. >***** >* January 19, 2014, two-year anniversary of my mother's death >* by Rick C. Hodgin >***** > >SET STATUS OFF >SET BELL OFF >SET DOHISTORY OFF >SET TALK OFF >SET STATUS BAR ON >SET SAFETY OFF >SET CPDIALOG OFF > >* Set the app paths >SET PROCEDURE TO custom_shape_rgn.prg ADDITIVE > >* Declare required region functions >#DEFINE RGN_AND 1 >#DEFINE RGN_OR 2 >#DEFINE RGN_XOR 3 > >DECLARE LONG CreateRectRgn ; > IN WIN32API ; > LONG nLeftRect, ; > LONG nTopRect, ; > LONG nRightRect, ; > LONG nBottomRect > >DECLARE LONG CombineRgn ; > IN WIN32API ; > LONG hrgnDest, ; > LONG hrgnSrc1, ; > LONG hrgnSrc2, ; > LONG fnCombineMode > >DECLARE LONG SetWindowRgn ; > IN WIN32API ; > LONG hWnd, ; > LONG hRgn, ; > LONG bRedraw > >DECLARE LONG DeleteObject ; > IN WIN32API ; > LONG hObject > >* Build our mask. In this example, each character will be a mask bit and will >* be multiplied into a (lnMult*lnMult) region. >PUBLIC gaMask >DECLARE gaMask[22] >gaMask[1] = "..OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.." >gaMask[2] = ".O............................................................................O." >gaMask[3] = ".O.......O....................................................................O." >gaMask[4] = ".O.......O.............................OO.OO...................OOOOOOOOO......O." >gaMask[5] = "..O......O.........OO.................OOOOOOO.................O.........O....O.." >gaMask[6] = "..O...OOOOOOO......OO..................OOOOO..................O..O...O..O....O.." >gaMask[7] = ".O.......O.........OO...................OOO...................O.........O.....O." >gaMask[8] = ".O.......O.........OO....................O....................O.OOOOOOO.O.....O." >gaMask[9] = ".O.......O.........OO.....OOOOOO....OO.......OO....OOOOOO.....O...OOO...O.....O." >gaMask[10] = "..O......O.........OO....OO....OO....OO.....OO....OO....OO....O.........O....O.." >gaMask[11] = "..O......O.........OO...OO......OO...OO.....OO...OOOOOOOOO.....OOOOOOOOO.....O.." >gaMask[12] = ".O.......O.........OO...OO......OO....OO...OO....OO...........................O." >gaMask[13] = ".O.......O.........OO....OO....OO......OO.OO......OO....OO....................O." >gaMask[14] = "..O......O.........OO.....OOOOOO........OOO........OOOOOO....................O.." >gaMask[15] = "..OO.....O.................................................................OO..." >gaMask[16] = "..OO.....O.................................................................OO..." >gaMask[17] = "...OO....O......OOOOOOOOOOOOOOOO..............OOOOOOOOOOOOOOOO............OO...." >gaMask[18] = "....OOOOOOOOOOOOO..............OOOOOOOOOOOOOOOO..............OOOOOOOOOOOOOO....." >gaMask[19] = "................................................................................" >gaMask[20] = "................................................................................" >gaMask[21] = "................................................................................" >gaMask[22] = "................................................................................" >PUBLIC gnMult >gnMult = 12 > > >* Display the region form >*_vfp.Visible = .f. >loForm = CREATEOBJECT("RectForm") >loForm.mth_setup(gnMult, LEN(gaMask[1]) * gnMult, ALEN(gaMask,1) * gnMult) > >* Wait until we're done >READ EVENTS > >DEFINE CLASS ClickShape AS Shape > FUNCTION Click > thisForm.Click >ENDDEFINE > >DEFINE CLASS EyeTimer AS Timer > Interval = 33 > Enabled = .t. > > FUNCTION Timer > LOCAL l > * Reset the eye line > gaMask[20] = REPLICATE(".", LEN(gaMask[20])) > gaMask[21] = REPLICATE(".", LEN(gaMask[21])) > > * Draw the new eye position > gaMask[20] = STUFF(gaMask[20], thisForm.eye_pos, 2, "OO") > gaMask[21] = STUFF(gaMask[21], thisForm.eye_pos, 2, "OO") > gaMask[20] = STUFF(gaMask[20], thisForm.eye_pos / 2, 2, "OO") > gaMask[21] = STUFF(gaMask[21], thisForm.eye_pos / 2, 2, "OO") > gaMask[20] = STUFF(gaMask[20], thisForm.eye_pos / 4, 2, "OO") > gaMask[21] = STUFF(gaMask[21], thisForm.eye_pos / 4, 2, "OO") > gaMask[20] = STUFF(gaMask[20], thisForm.eye_pos / 8, 2, "OO") > gaMask[21] = STUFF(gaMask[21], thisForm.eye_pos / 8, 2, "OO") > gaMask[20] = STUFF(gaMask[20], LEN(gaMask[20]) - (thisForm.eye_pos / 8), 2, "OO") > gaMask[21] = STUFF(gaMask[21], LEN(gaMask[20]) - (thisForm.eye_pos / 8), 2, "OO") > gaMask[20] = STUFF(gaMask[20], LEN(gaMask[20]) - (thisForm.eye_pos / 4), 2, "OO") > gaMask[21] = STUFF(gaMask[21], LEN(gaMask[20]) - (thisForm.eye_pos / 4), 2, "OO") > gaMask[20] = STUFF(gaMask[20], LEN(gaMask[20]) - (thisForm.eye_pos / 2), 2, "OO") > gaMask[21] = STUFF(gaMask[21], LEN(gaMask[20]) - (thisForm.eye_pos / 2), 2, "OO") > gaMask[20] = STUFF(gaMask[20], LEN(gaMask[20]) - thisForm.eye_pos, 2, "OO") > gaMask[21] = STUFF(gaMask[21], LEN(gaMask[20]) - thisForm.eye_pos, 2, "OO") > > * Move the eye for the next position > thisForm.eye_pos = thisForm.eye_pos + thisForm.eye_inc > DO CASE > CASE thisForm.eye_pos > LEN(gaMask[20]) - 2 > thisForm.eye_inc = -1 > CASE thisForm.eye_pos < 2 > thisForm.eye_inc = 1 > ENDCASE > > * Reset the region mask > thisForm.mth_setup(gnMult, -1, -1) >ENDDEFINE > >DEFINE CLASS RectForm AS form > Left = -1 > Top = -1 > Visible = .f. > BackColor = RGB(255,255,0) && Yellow > BorderStyle = 3 && Single pixel border > ShowWindow = 2 && Top level form > > * Create an eye that moves back and forth > eye_array = .NULL. && Array > eye_pos = 1 && Position of the rotating eye > eye_inc = 1 && Move forward > > FUNCTION Click > * Release the window on any click > thisForm.Release > > FUNCTION Init > thisForm.AddObject("timer1", "EyeTimer") > > FUNCTION Unload > * And prepare to exit the program > CLEAR EVENTS > > FUNCTION mth_setup > LPARAMETERS tnMult, tnWidth, tnHeight > LOCAL lnI, lnRow, lnCol, lo, lnLeft, lnTop, lnWidth, lnHeight, lcName, lnWindowRgn, lnThisBlockRgn, lnCombinedRgn > > * Store the array for use with the eye timer > eye_array = gaMask > > * Set the parameters > lnWidth = IIF(tnWidth = -1, thisForm.Width - (SYSMETRIC(3) * 2), tnWidth) > lnHeight = IIF(tnHeight = -1, thisForm.Height - (SYSMETRIC(4) * 2), tnHeight) > lnWidth = SYSMETRIC(3) + lnWidth + SYSMETRIC(3) > lnHeight = SYSMETRIC(4) + lnHeight + SYSMETRIC(4) > lnLeft = SYSMETRIC(3) > lnTop = SYSMETRIC(4) + SYSMETRIC(9) > IF tnWidth != -1 AND tnHeight != -1 > thisForm.Width = lnWidth > thisForm.Height = lnHeight > ENDIF > > * Create the base region > lnWindowRgn = CreateRectRgn(0, 0, 1920*2, 1080*2) > > * Build region rectangles and overlay the boxes which will provide the outline > * Iterate for every row > FOR lnRow = 1 to ALEN(gaMask, 1) > > * Iterate for every column on that row > FOR lnCol = 1 to LEN(gaMask[lnRow]) > > * Is this a hole? > IF SUBSTR(gaMask[lnRow], lnCol, 1) != "." > * Yes > > IF lnRow < 19 > * Create the color object > lcName = "shp" + TRANSFORM(lnRow) + "_" + TRANSFORM(lnCol) > IF TYPE("thisForm.&lcName") != "O" > thisForm.addObject(lcName, "ClickShape") > WITH thisForm.&lcName > .left = (lnCol * tnMult) - 2 > .top = (lnRow * tnMult) - 2 > .width = tnMult + 4 > .height = tnMult + 4 > .backColor = RGB(0,0,0) && Black > .Visible = .t. && Make it visible upon the form > ENDWITH > ENDIF > ENDIF > > * Create the associated region > lnThisBlockRgn = CreateRectRgn(lnLeft + (lnCol*tnMult), ; > lnTop + (lnRow*tnMult), ; > lnLeft + ((lnCol+1)*tnMult), ; > lnTop + ((lnRow+1)*tnMult)) > > * Combine the two regions by removing this block > CombineRgn(lnWindowRgn, lnWindowRgn, lnThisBlockRgn, RGN_XOR) > > * Delete the temporary block region from our collective memories. May it region in peace. > DeleteObject(lnThisBlockRgn) > > ENDIF > > NEXT > > NEXT > > * Tell the window to respect the drawing region > SetWindowRgn(thisForm.hWnd, lnWindowRgn, 1) > > * When all processing is completed, make it visible > * Reposition after resize > IF thisForm.Left = -1 AND thisForm.Top = -1 > thisForm.Left = (_screen.Width - thisForm.Width) / 2 > thisForm.Top = (_screen.Height - thisForm.Height) / 2 > ENDIF > thisForm.visible = .t. > > * Refresh > thisForm.Refresh > DOEVENTS > >ENDDEFINE