353 lines
16 KiB
Rexx
353 lines
16 KiB
Rexx
|
/*----------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* 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:"
|