rexx-things/modules/windows/oodialog/userGuide/exercises/Exercise08/Support/DragMgr.rex
2025-03-12 20:50:48 +00:00

353 lines
16 KiB
Rexx
Executable File

/*----------------------------------------------------------------------------*/
/* */
/* 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. */
/* */
/*----------------------------------------------------------------------------*/
/* ooDialog User Guide - Exercise08
Support - DragMgr v01-00 26Jun13
---------------------
A singleton component that manages direct manipulation.
Notes: A 'source' view is a dialog that's "picked up" by pressing and holding
button 1 (usually the left button) of the mouse.
A 'target' view is a dialog that's dropped onto by releasing
button 1 over the target dialog.
Interface DragMgr {
setTarget
setSource
removeDlg
list lists tables of source & target dialogs.
dmPickup captures mouse - i.e. sets the mouse capture to the window
of this mouse instance.
moving If over a target (as supered by a dlg instance):
- check if this is a valid target AND is topmost window
- If over a valid drop area send dmQueryDrop(sourceDlg,mousePos)
to target.
- If response is .true then show dropOKCursor
else show noDropCursor (system-provided).
dmDrop - If cursor is no-drop then no-op.
Else send dmDrop(sourceDlg) to drop target.
}
Changes:
v01-00 06Jun13: First version.
18Jun13: Changed 'drop' method name to 'dmDrop'.
26Jun13: Change 'queryTables' method name to 'list' (to conform with
other Managers).
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::REQUIRES ooDialog.cls
::REQUIRES "Order\OrderModelsData.rex"
/*//////////////////////////////////////////////////////////////////////////////
============================================================================*/
::CLASS DragMgr PUBLIC
::ATTRIBUTE targetDialogs PRIVATE -- dlg - hwnd, dropArea
::ATTRIBUTE sourceDialogs PRIVATE -- dlg - mouse, dropOkCursor, pickupArea
::ATTRIBUTE dragInProgress
--::ATTRIBUTE draggingSourceDlg PRIVATE
/*----------------------------------------------------------------------------
init - initialises the Drag Manager
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD init
expose icons dragging cursorIsNoDrop noDropCursor
.local~my.DragMgr = self
--say "DragMgr-init-01: .local~my.DragMgr =" .local~my.DragMgr
self~dragInProgress = .false
self~targetDialogs = .Table~new -- Index = dlg id
-- Item = an Array: hwnd, dropArea,
self~sourceDialogs = .Table~new -- Index = dlg id,
-- Item = an Array: mouse, cursor, pickupArea
noDropCursor = .Mouse~loadCursor("NO")
if noDropCursor == 0 then do
say "DragManager-init-02:" .HRSdm~badNoDropCursor .SystemErrorCode
end
cursorIsNoDrop = .false
dragging = .false
return self
/*----------------------------------------------------------------------------
setTarget - Adds a target view component to the Targets table
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD setTarget PUBLIC
--expose targetDialogs
use strict arg dlg, hwnd, dropArea
items = .Array~new
items[1] = hwnd; items[2] = dropArea
self~targetDialogs[dlg] = items
/*----------------------------------------------------------------------------
setSource - Adds a source view component to the Targets table
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD setSource PUBLIC
--expose sourceDialogs dropOkCursor
--use strict arg dlg, mouse, cursorFile, pickupArea, control
use strict arg sourceWin, mouse, cursorFile, pickupArea, srcDlg -- ***
-- cursorFile is relative path and filename e.g. "bmp\customer.cur".
--say "DragManager-setSource-01: sourceWin, Area =" sourceWin||"," pickupArea
dropOkCursor = .Mouse~loadCursorFromFile(cursorFile)
if dropOkCursor == 0 then do
say "DragManager-setSource-02:" .HRSdm~badOkCursor .SystemErrorCode
end
items = .Array~new
items[1] = mouse; items[2] = dropOkCursor;
items[3] = pickupArea; items[4] = srcDlg
self~sourceDialogs[sourceWin] = items
/*----------------------------------------------------------------------------
RemoveDlg - Removes a dialog from the Targets table when the dialog closes.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD removeDlg PUBLIC
use strict arg dlg
-- Check in SourceDlgs:
self~sourceDialogs~remove(dlg)
self~targetDialogs~remove(dlg)
/*----------------------------------------------------------------------------
dmPickup - Handles drag initiation when the user "picks up" a dialog.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD dmPickup PUBLIC
expose cursorIsNoDrop dragging dropOkCursor mouse noDropCursor oldCursor overTarget
use strict arg sourceWin, keyState, mousePos
--say "DragMgr-dmPickup-00; sourceWin =" sourceWin
arrItems = self~sourceDialogs[sourceWin] -- mouse,srcCursor,pickupArea,sourceDlg
mouse = arrItems[1]
dropOkCursor = arrItems[2]
dragging = .false
--trace i
if keyState \== 'lButton' | \ mousePos~inRect(arrItems[3]) then return .false
--trace off
if mouse~dragDetect(mousePos) then do
--say "DragManager-dmPickup-01: dropOkCursor =" dropOkCursor
if dropOkCursor == 0 then do
nop --say "DragManager-dmPickup-02:" .HRSdm~badOkCursor .SystemErrorCode
end
--say 'DragManager-dmPickup-03: Detected dragging.'
mouse~capture()
oldCursor = mouse~setCursor(noDropCursor)
cursorIsNoDrop = .true
dragging = .true
validTarget = .false
overTarget = .false
end
--say "DragManager-dmPickup-04: dragging =" dragging
return
/*----------------------------------------------------------------------------
moving - Handles mouse movements - detects when mouse over a dialog, and if
it's a 'target' dialog, asks it whether it will accept a drop.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD moving PUBLIC
expose cursorIsNoDrop dragging dropOkCursor mouse noDropCursor overTarget dropTarget
use arg sourceWin, sourceDlg, keyState, mousePos
-- overTarget - true when the cursor is over a potential target dialog,
-- regardless of whether the target refuses a drop or not.
-- sourceWin is the window (dialog or control) that has captured the mouse.
-- Note: new APIs introduced in ooDialog Build 7449
--say "DragManager-moving-00; sourceDlg, sourceWin, dragging =" sourceDlg||"," sourceWin||"," dragging
if \dragging then return
--say "DragManager-moving-00A: Flags:" cursorIsNoDrop dragging overTarget
-- Find out if mouse is over a target dialog:
targetDlg = 0
do i over self~targetDialogs -- items: 1 = hwnd, 2 = droparea
targetHwnd = self~targetDialogs[i][1]
droparea = self~targetDialogs[i][2]
--say "DragMgr-moving-00B: targetHwnd, dropArea =" targetHwnd||"," dropArea
-- Prevent showing drop when over a target that is under another window:
screenPt = mousePos~copy() -- Point in source dialog (i.e. top left of dlg is 0,0)
--say "DragManager-moving-01: screenPt =" screenPt
sourceWin~client2screen(screenPt)
--sourceDlg~client2screen(screenPt) -- screenPt is set to screen position (i.e. top left of screen is 0,0)
--say "DragManager-moving-02: screenPt =" screenPt
screenHwnd = .DlgUtil~windowFromPoint(screenPt) -- Get hwd of topmost window that mouse is over
--say "DragManager-moving-03: screenHwnd =" screenHwnd
pDlg = mousePos~copy
--sourceDlg~mapWindowPoints(targetHwnd, pDlg) -- MousePos relative to targetHwnd
sourceWin~mapWindowPoints(targetHwnd, pDlg) -- MousePos relative to targetHwnd
--say "DragManager-moving-04: pDlg =" pDlg
childHwnd = i~childWindowFromPoint(pDlg) -- Get the hwnd visible under mouse pointer
--say "DragManager-moving-05: childHwnd, pDlg =" childHwnd||"." pDlg
if screenHwnd == childHwnd then do
p1 = mousePos~copy()
--sourceDlg~mapWindowPoints(targetHwnd,p1)
sourceWin~mapWindowPoints(targetHwnd,p1)
--say "DragManager-moving-06: p1 =" p1
if p1~inRect(droparea) then do
targetDlg = i
-- next two statements for debug only
--tgtNumber = i~queryNumber
--say "DragManager-moving-07: Target found - hwnd =" targetHwnd tgtNumber
leave -- Stop looping - target found!
end
end
end
--say "DragManager-moving-060."
if targetDlg \= 0 then do -- If we're over a target
if targetDlg = sourceDlg then return -- If target is also the source
-- then it's not a target (in this version!).
if \overTarget then do -- if first time over target
--Get the model class for the source View:
objectMgr = .local~my.ObjectMgr
sourceClassName = objectMgr~modelClassFromView(sourceDlg)
targetClassName = objectMgr~modelClassFromView(targetDlg)
--say "DragMgr-moving-06a: source Class =" sourceClassName
--say "DragMgr-moving-06b: target Class =" targetClassName
--parse value a~class with . className .
interpret "r = ."||targetClassName||"~dmQueryDrop("||sourceClassName||")"
--say "DragManager-moving-07a: first time - queryDrop returned" r
if r = .true then do -- if target accepts a drop
validTarget = .true
dropTarget = targetDlg -- for drop method ...
end
else do -- if target refuses drop
validTarget = .false
overTarget = .true
dropTarget = .false
return
end
-- It's a valid target!
overTarget = .true
mouse~setCursor(dropOkCursor)
cursorIsNoDrop = .false
end
end
else do -- Not over a target
if overTarget then do -- Mouse has just come off target
validTarget = .false
overTarget = .false
mouse~setCursor(noDropCursor)
cursorIsNoDrop = .true
dropTargetDlg = 0
end
end
/*----------------------------------------------------------------------------
dmDrop - Handles things when the user drops onto a target.
Invoked by "View" (the superclass).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD dmDrop PUBLIC
expose cursorIsNoDrop dragging mouse oldCursor dropTarget
use strict arg sourceDlg, keyState, mousePos
--say "DragManager-dmDrop-01: the mouse is at ("mousePos~x", "mousePos~y")"
--say "DragManager-dmDrop-02: cursorIsNoDrop =" cursorIsNoDrop
if dragging then do
okayToDrop = (cursorIsNoDrop \== .true) -- if cind = .false then okToDrop is true;
-- if cind = .true then okToDrop is false
dragging = .false
cursorIsNoDrop = .false
mouse~releaseCapture()
mouse~setCursor(oldCursor)
--say "DragManager-dmDrop-02a: mouse released; old cursor set."
-- Jiggle the mouse so it is redrawn immediately (OS: seems to make no diff.)
p = mouse~getCursorPos; p~incr; mouse~setCursorPos(p)
if okayToDrop then do
--say "DragManager-dmDrop-03: sourceDlg =" sourceDlg
-- objectMgr = .local~my.ObjectMgr
-- sourceClassName = objectMgr~modelClassFromView(sourceDlg)
-- targetClassName = objectMgr~modelClassFromView(targetDlg)
objectMgr = .local~my.ObjectMgr
sourceModelId = objectMgr~modelIdFromView(sourceDlg)
dropTarget~dmDrop(sourceModelId, sourceDlg)
--say "DragManager-dmDrop-04: Drop Happened OK!!"
end
else nop --say "DragManager-dmDrop-05: Drop Did Not Occur."
end
return
/*----------------------------------------------------------------------------
list - A debug mehod that lists source and target dialogs on the console.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD list PUBLIC -- Debug method
say; say "======================================="
say "DragManager Tables"
say "-------------------------------------"
say "Sources:"
--say "asking dlg =" dlg
do i over self~SourceDialogs
say "i =" i
items = self~SourceDialogs[i]
say "mouse = " items[1]
say "cursor = " items[2]
say "area = " items[3]
say "dialog = " items[4]
end
say "-------------------------------------"
say "Targets:"
arr = self~targetDialogs[dlg]
do i over self~targetDialogs
say "i =" i
items = self~TargetDialogs[i]
say "hwnd = " items[1]
say "dropArea = " items[2]
end
say "======================================="; say
/*============================================================================*/
/*==============================================================================
Human-Readable Strings (HRSdm) v00-01 23Jan12
--------
The HRSdm class provides constant character strings for user-visible messages.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS HRSdm PRIVATE -- Human-Readable Strings
::CONSTANT badNoDropCursor "Error loading NoDrop Cursor, sys error code:"
::CONSTANT badOkCursor "Error loading DropOK Cursor, sys error code:"