/*----------------------------------------------------------------------------*/ /* */ /* Copyright (c) 2011-2014 Rexx Language Association. All rights reserved. */ /* */ /* This program and the accompanying materials are made available under */ /* the terms of the Common Public License v1.0 which accompanies this */ /* distribution. A copy is also available at the following address: */ /* https://www.oorexx.org/license.html */ /* */ /* Redistribution and use in source and binary forms, with or */ /* without modification, are permitted provided that the following */ /* conditions are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the distribution. */ /* */ /* Neither the name of Rexx Language Association nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */ /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */ /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */ /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*----------------------------------------------------------------------------*/ /** * This example program demonstrates one approach to adding drag-and-drop to an * ooDialog program using the .Mouse class. */ sd = locate() .application~setDefaults('O', sd'dragNdrop.h', .false) dlg = .DreamTeamDlg~new(sd'dragNdrop.rc', IDD_NFL_DLG) if dlg~initCode == 0 then do dlg~execute("SHOWTOP", IDI_DLG_OOREXX) end ::requires "ooDialog.cls" ::class 'DreamTeamDlg' subclass RcDialog ::method init expose dropOkCursor noDropCursor cursorIsNoDrop dragging forward class (super) continue -- This will load a cursor from a file. The file has to actually be a cursor -- or the method will fail. The operating system will refuse to load anything -- but an actual cursor. The return is an .Image object. dropOkCursor = .Mouse~loadCursorFromFile(.application~srcDir"dragging.cur") if dropOkCursor == 0 then do say 'Error loading Drop Ok Cursor system error code:' .SystemErrorCode self~initCode = 1 return self~initCode end -- This loads the system's predefined NO cursor. Again the return is a .Image -- object. noDropCursor = .Mouse~loadCursor("NO") if noDropCursor == 0 then do say 'Error loading No Drop Cursor, system error code:' .SystemErrorCode self~initCode = 1 return self~initCode end cursorIsNoDrop = .false dragging = .false return 0 ::method initDialog expose lvNFL lvWest lvEast noDropCursor dragItem nfl2west nfl2east lvNFL = self~newListView(IDC_LV_NFL) self~setUpListView(lvNFL) lvWest = self~newListView(IDC_LV_WEST) self~setUpListView(lvWest) lvEast = self~newListView(IDC_LV_EAST) self~setUpListView(lvEast) self~setMice self~mapDropTargets dragItem = .nil /** mapDropTargets() * */ ::method mapDropTargets private expose lvNFL lvWest lvEast nfl2west nfl2east west2nfl west2east east2nfl east2west nfl2west = lvWest~clientRect lvWest~mapWindowPoints(lvNFL~hwnd, nfl2west) nfl2east = lvEast~clientRect lvEast~mapWindowPoints(lvNFL~hwnd, nfl2east) west2nfl = lvNFL~clientRect lvNFL~mapWindowPoints(lvWest~hwnd, west2nfl) west2east = lvEast~clientRect lvEast~mapWindowPoints(lvWest~hwnd, west2east) east2nfl = lvNFL~clientRect lvNFL~mapWindowPoints(lvEast~hwnd, east2nfl) east2west = lvWest~clientRect lvWest~mapWindowPoints(lvEast~hwnd, east2west) ::method doDrag private expose oldCursor noDropCursor cursorIsNoDrop dragging use arg lv, index, p, mouse mouse~capture oldCursor = mouse~setCursor(noDropCursor) di = .DragItem~new(lv, index, p, mouse) cursorIsNoDrop = .true dragging = .true return di ::method nflOnLBdown unguarded expose lvNFL dragItem use arg keyState, p, mouse index = lvNFL~hitTestInfo(p) if keyState \== 'lButton' | index = -1 then return .false lvNFL~assignFocus lvNFL~focus(index) lvNFL~select(index) if mouse~dragDetect(p) then do dragItem = self~doDrag(lvNFL, index, p, mouse) return .true end return .false ::method nflOnLBup unguarded expose oldCursor cursorIsNoDrop dragging lvNFL lvWest lvEast dragItem nfl2west nfl2east use arg keyState, p, mouse if dragging then do okayToDrop = (cusorIsNoDrop \== .true) dragging = .false cursorIsNoDrop = .false mouse~releaseCapture mouse~setCursor(oldCursor) if okayToDrop & dragItem \== .nil then do if p~inRect(nfl2west) then do dragItem~target = lvWest end else if p~inRect(nfl2east) then do dragItem~target = lvEast end else do -- Theoretically this can not happen, but just to be sure... dragItem = .nil return 0 end -- The point p is in client coordinates of the NFL list view. We are -- going to map that point back to the client coordinates of the list view -- where the row is being dropped. Then the drag item can determine where -- the insertion poing for the row should be in the target list view. lvNFL~mapWindowPoints(dragItem~target~hwnd, p) dragItem~drop(p) dragItem = .nil end end return 0 ::method nflOnMove unguarded expose dragging dropOkCursor noDropCursor cursorIsNoDrop nfl2west nfl2east use arg keyState, p, mouse if dragging then do if p~inRect(nfl2west) then do if cursorIsNoDrop then do mouse~setCursor(dropOkCursor) cursorIsNoDrop = .false end end else if p~inRect(nfl2east) then do if cursorIsNoDrop then do mouse~setCursor(dropOkCursor) cursorIsNoDrop = .false end end else do if \ cursorIsNoDrop then do mouse~setCursor(noDropCursor) cursorIsNoDrop = .true end end end return 0 ::method westOnLBdown unguarded expose lvWest dragItem use arg keyState, p, mouse index = lvWest~hitTestInfo(p) if keyState \== 'lButton' | index = -1 then return .false lvWest~assignFocus lvWest~focus(index) lvWest~select(index) if mouse~dragDetect(p) then do dragItem = self~doDrag(lvWest, index, p, mouse) return .true end return .false ::method westOnLBup unguarded expose oldCursor cursorIsNoDrop dragging lvNFL lvWest lvEast dragItem west2nfl west2east use arg keyState, p, mouse if dragging then do okayToDrop = (cusorIsNoDrop \== .true) dragging = .false cursorIsNoDrop = .false mouse~releaseCapture mouse~setCursor(oldCursor) if okayToDrop & dragItem \== .nil then do if p~inRect(west2nfl) then do dragItem~target = lvNFL end else if p~inRect(west2east) then do dragItem~target = lvEast end else do -- Theoretically this can not happen, but just to be sure... dragItem = .nil return 0 end -- The point p is in client coordinates of the West list view. We are -- going to map that point back to the client coordinates of the list view -- where the row is being dropped. Then the drag item can determine where -- the insertion poing for the row should be in the target list view. lvWest~mapWindowPoints(dragItem~target~hwnd, p) dragItem~drop(p) dragItem = .nil end end return 0 ::method westOnMove unguarded expose dragging dropOkCursor noDropCursor cursorIsNoDrop west2nfl west2east use arg keyState, p, mouse if dragging then do if p~inRect(west2nfl) then do if cursorIsNoDrop then do mouse~setCursor(dropOkCursor) cursorIsNoDrop = .false end end else if p~inRect(west2east) then do if cursorIsNoDrop then do mouse~setCursor(dropOkCursor) cursorIsNoDrop = .false end end else do if \ cursorIsNoDrop then do mouse~setCursor(noDropCursor) cursorIsNoDrop = .true end end end return 0 ::method eastOnLBdown unguarded expose lvEast dragItem use arg keyState, p, mouse index = lvEast~hitTestInfo(p) if keyState \== 'lButton' | index = -1 then return .false lvEast~assignFocus lvEast~focus(index) lvEast~select(index) if mouse~dragDetect(p) then do dragItem = self~doDrag(lvEast, index, p, mouse) return .true end return .false ::method eastOnLBup unguarded expose oldCursor cursorIsNoDrop dragging lvNFL lvWest lvEast dragItem east2nfl east2west use arg keyState, p, mouse if dragging then do okayToDrop = (cusorIsNoDrop \== .true) dragging = .false cursorIsNoDrop = .false mouse~releaseCapture mouse~setCursor(oldCursor) if okayToDrop & dragItem \== .nil then do if p~inRect(east2nfl) then do dragItem~target = lvNFL end else if p~inRect(east2west) then do dragItem~target = lvWest end else do -- Theoretically this can not happen, but just to be sure... dragItem = .nil return 0 end -- The point p is in client coordinates of the East list view. We are -- going to map that point back to the client coordinates of the list view -- where the row is being dropped. Then the drag item can determine where -- the insertion poing for the row should be in the target list view. lvEast~mapWindowPoints(dragItem~target~hwnd, p) dragItem~drop(p) dragItem = .nil end end return 0 ::method eastOnMove unguarded expose dragging dropOkCursor noDropCursor cursorIsNoDrop east2nfl east2west use arg keyState, p, mouse if dragging then do if p~inRect(east2nfl) then do if cursorIsNoDrop then do mouse~setCursor(dropOkCursor) cursorIsNoDrop = .false end end else if p~inRect(east2west) then do if cursorIsNoDrop then do mouse~setCursor(dropOkCursor) cursorIsNoDrop = .false end end else do if \ cursorIsNoDrop then do mouse~setCursor(noDropCursor) cursorIsNoDrop = .true end end end return 0 ::method setMice private expose mLVnfl mLVwest mLVeast lvNFL lvWest lvEast mLVnfl = .Mouse~new(lvNFL) mLVwest = .Mouse~new(lvWest) mLVeast = .Mouse~new(lvEast) mLVnfl~connectEvent('LBUTTONDOWN', nflOnLBdown) mLVnfl~connectEvent('LBUTTONUP', nflOnLBup) mLVnfl~connectEvent('MOUSEMOVE', nflOnMove) mLVwest~connectEvent('LBUTTONDOWN', westOnLBdown) mLVwest~connectEvent('LBUTTONUP', westOnLBup) mLVwest~connectEvent('MOUSEMOVE', westOnMove) mLVeast~connectEvent('LBUTTONDOWN', eastOnLBdown) mLVeast~connectEvent('LBUTTONUP', eastOnLBup) mLVeast~connectEvent('MOUSEMOVE', eastOnMove) ::method setUpListView private use strict arg lv lv~addExtendedStyle("GRIDLINES DOUBLEBUFFER FULLROWSELECT") lv~insertColumnPX(0, 'Player', 105, 'LEFT') lv~insertColumnPX(1, 'Team', 115, 'CENTER') lv~insertColumnPX(2, 'Position', 65, 'CENTER') lv~insertColumnPX(3, 'Rating', 65, 'CENTER') if lv~id == .constDir[IDC_LV_NFL] then do playerRows = self~getPlayers do l over playerRows lv~addRow( , , l~player, l~team, l~pos, l~rating) end end ::method getPlayers private rows = .Array~new fileObj = .stream~new(.application~srcDir"nflPlayers.txt") players = fileObj~makeArray do line over players line = line~strip if line~length == 0 | line~abbrev("#") | line~abbrev("/*") then iterate parse var line name', 'team', 'p', 'rating . r = .Directory~new r~player = name r~team = team r~pos = p r~rating = rating rows~append(r) end fileObj~close return rows /* Class: DragItem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\ Drag items are an encapsulation of the data needed to drag and drop one row of a list view to another. \* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ ::class 'DragItem' ::attribute target ::method init expose lv index row target use arg lv, index, p, mouse row = .Directory~new lv~getItemInfo(index, row) row~player = row~text lv~getItemInfo(index, row, 1) row~team = row~text lv~getItemInfo(index, row, 2) row~pos = row~text lv~getItemInfo(index, row, 3) row~rating = row~text target = .nil ::method drop expose lv index row target use strict arg pt = 0 if target \== .nil then do -- Drop the row at the end of the list by default. targetIndex = target~items if pt~isA(.Point) then do i = target~hitTestInfo(pt) if i <> -1 then targetIndex = i end target~addRow(targetIndex, , row~player, row~team, row~pos, row~rating) lv~delete(index) count = lv~items if count <> 0 then do if index == count then lv~select(index - 1) else lv~select(index) end end