Jump to content
Sign in to follow this  
qwert

Modify drag&drop behavior for RichEdit text?

Recommended Posts

qwert

Oct 2 edit: added PNG example to show difference in behavior.

The following example demonstrates the default behavior of dragging text from one RichEdit field to another. The text is removed from the first field as a result of it being dropped into the second.

include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
#Include <GuiScrollBars.au3>
#include <ScrollBarConstants.au3>
 
Opt("GUIOnEventMode", 1)
 
$Form = GUICreate("", 600, 300, -1, -1,-1 ,$WS_EX_WINDOWEDGE+$WS_EX_TOPMOST)
GUISetOnEvent($GUI_EVENT_CLOSE, "Terminate")
GUICtrlCreateLabel("First Rich Text Field", 20, 20)
GUICtrlCreateLabel("Second Rich Text Field", 300, 20)
GUICtrlCreateLabel("Enter text into the first field ... then highlight it and drag/drop it into the second field.", 20, 250, 560, -1)
GUICtrlSetFont(-1, 11, 400, -1, "Arial")
GUICtrlCreateLabel("I need the dropped text to remain in the first field ... and preferably remain highlighted.", 20, 270, 560, -1)
GUICtrlSetFont(-1, 10, 800, -1, "Arial")
 
$rich1 = _GUICtrlRichEdit_Create($Form, "", 20, 40, 200, 200, BitOR($ES_WANTRETURN, $ES_MULTILINE, $WS_VSCROLL))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    _GUIScrollBars_ShowScrollBar($rich1, $SB_VERT, True)
 
$rich2 = _GUICtrlRichEdit_Create($Form, "", 300, 40, 200, 200, BitOR($ES_WANTRETURN, $ES_MULTILINE, $WS_VSCROLL))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    _GUIScrollBars_ShowScrollBar($rich2, $SB_VERT, True)
 
GUISetState(@SW_SHOW)
 
While 1
Sleep(50)
WEnd
 
Func Terminate()
    _GUICtrlRichEdit_Destroy($rich1)
    _GUICtrlRichEdit_Destroy($rich2)
    Exit
EndFunc

How can I cause the drag&drop operation to leave the text in the first field ... and highlighted?

A more worrisome behavior occurs when I test with WordPad. Any text I drag to one of the RichEdit fields disappears from WordPad. I've never noticed that effect with other applications. For example, you can drag text from a WordPad window to another WordPad window without changing the original ... and it also remains highlighted in the first window, just like I need.

I will appreciate any suggestions. Thanks.post-29172-0-57629000-1317532297_thumb.p

Edited by qwert

Share this post


Link to post
Share on other sites
qwert

The plot thickens. Yes, holding the Ctrl key changes the behavior from a Move to a Copy. Based on your suggestion, I've delved into drag and drop and found that it's dependent on how the object is defined. Here's a relevant description from msdn: msdn link

In particular, it has this description:

Beginning a Drag-and-Drop Operation

To begin a drag-and-drop operation, you call the DoDragDrop method of a Windows Forms control. The DoDragDrop method is implemented on the System.Windows.Forms.Control class, which means that it is available on all controls within the Windows Forms namespace.

The DoDragDrop method takes two arguments: the data to be dragged, and the drag operations that this control allows.

... then in the code example:

DragDropEffects.Copy Or DragDropEffects.Move...

where the full set of operation choices are:

All -- The data is copied, removed from the drag source, and scrolled in the target.

Copy -- The data is copied to the target.

Link -- The data is linked to the target.

Move -- The data is moved to the target.

None -- The target does not accept the data.

Scroll Scrolling is about to start or currently occurring in the target.

As a result, I've looked at the functions in GuiRichEdit.au3. I can see where it does a GetDragDropEffect, but I can't see where it is ever set. I've never worked with objects beyond the simple examples shown in the help file, but it looks like there needs to be one more parameter or function in the GuiRichEdit UDF.

So, to clearly restate the problem I'm looking to solve:

Mainly from window to window, it's a little unnerving to see text disappear from the source. For example, when dragging a section of a script from SciTE to WordPad, you don't expect the lines to disappear from the script you're working on. Requiring the Ctrl key in order to avert the loss of text seems a little 'unfriendly' to the user and certainly not intuitive.

Thanks for your assistance. I'm hoping someone (ProgAndy?) can shed light on the details of this situation.

Share this post


Link to post
Share on other sites
qwert

I've finally gotten back to this problem. Transfers to and from Wordpad now work as expected (the text remains in place).

What I'm striving for is exactly the same behavior when dragging and dropping into another field in the same GUI. I've attached a PNG to my original post to explain the difference.

Any suggestions for changing the GUI's default behavior will be GREATLY appreciated.

Share this post


Link to post
Share on other sites
qwert

I'm finally back working on the issue and thought I might ask once again about the default behavior of dragging/dropping Rich Text:

The <example in the first post> demonstrates the default behavior of dragging text from one RichEdit field to another. The text is removed from the first field as a result of it being dropped into the second.

Would anyone happen to have a suggestion about how to change the default behaviour? (i.e., so that text isn't removed from the first field.)

Thanks for any help.

Share this post


Link to post
Share on other sites
qwert

Although I don't see anything in the release notes, something seems to have changed in the _GUICtrlRichEdit_Create function or the RichEdit UDFs in v3.3.8.0. The example in my first post no longer creates two edit blocks.

I would appreciate it if someone would confirm this behavior change by trying my script? If it fails, I'll post a report.

Thanks.

Share this post


Link to post
Share on other sites
AdmiralAlkex

Although I don't see anything in the release notes, something seems to have changed in the _GUICtrlRichEdit_Create function or the RichEdit UDFs in v3.3.8.0. The example in my first post no longer creates two edit blocks.

I would appreciate it if someone would confirm this behavior change by trying my script? If it fails, I'll post a report.

Thanks.

Work has already been done on the UDF by guinness and me (for #2077 and some other things), it should work in the next beta. This attachment should work for you in the interrim.

GuiRichEdit.zip

Edited by AdmiralAlkex

Share this post


Link to post
Share on other sites
qwert

Thank you for the quick response. That gets my example back on track.

Since you work with the details of the UDF, do you have any suggestions regarding the RichEdit drag and drop behavior I'm seeking?

Share this post


Link to post
Share on other sites
rover

I've solved the issue with the non-standard text drag and drop behaviour.

RichEdit text drag and drop operations now work the same as Wordpad with this modification.

The GetDragDropEffect callback has been modified to determine if the drag and drop operation is within the RichEdit, or between it and another source/destination.

$pdwEffect in the IRichEditOleCallback::GetDragDropEffect method is returning 3 (DROPEFFECT_COPY + DROPEFFECT_MOVE) for every drag and drop event.

It should be:

DROPEFFECT_COPY = 1 for no key or Ctrl key dragging between source and destination. (The drag cursor should have the + box for DROPEFFECT_COPY)

DROPEFFECT_MOVE = 2 for Alt key dragging between source and destination.

DROPEFFECT_COPY + DROPEFFECT_MOVE = 3 for dragging text within source RichEdit with no key, Ctrl or Alt key (Key modifiers alter the drag behaviour within the same RichEdit)

References:

IRichEditOleCallback::GetDragDropEffect method

http://msdn.microsoft.com/en-us/library/windows/desktop/bb774319(v=vs.85).aspx

pdwEffect Type: LPDWORD

Pointer to the variable that contains the effect used by a rich edit control.

When fDrag is TRUE, on return, its content is set to the effect allowable by the rich edit control.

When fDrag is FALSE, on return, the variable is set to the effect to use.

IDropSource::QueryContinueDrag method

http://msdn.microsoft.com/en-us/library/windows/desktop/ms690076(v=vs.85).aspx

grfKeyState [in]: The current state of the keyboard modifier keys on the keyboard.

Possible values can be a combination of any of the flags MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON.

Disclaimer:

If you are going to try this, please make a backup or use a renamed copy of GuiRichEdit.au3

Note: As of v3.3.8.0, you need to download the version of GuiRichEdit.au3 in post #7

Edit: Added additional handle checking, and MouseCoordMode option

I was getting the odd case where text dragged from Wordpad to an AutoIt RichEdit was cut instead of copied.

The problem is probably the least reliable area of this code: getting the source and destination handles.

(and not all draggable text sources/destinations will have readable handles)

This code just demonstrates the D&D issues.

The proper fix is probably some COM object magic

I noticed, memory usage increases with added text, but doesn't decrease when text deleted (occurs without this fix)

Replacement GetDragDropEffect function and vars for GuiRichEdit.au3

;Replace the function and add the vars to GuiRichEdit.au3
Global Const $DROPEFFECT_COPY = 1
Global Const $DROPEFFECT_MOVE = 2
Global Const $MK_ALT = 0x20
Global Const $MK_CONTROL = 0x8
Global $iMode, $hDragSource


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __RichCom_Object_GetDragDropEffect
; Description ...:
; Syntax.........: __RichCom_Object_GetDragDropEffect($pObject, $fDrag, $grfKeyState, $pdwEffect)
; Parameters ....:
; Return values .:
; Author ........:
; Modified.......: rover 2k12
; Remarks .......: Patch to demonstrate issue with RichEdit defaulting to DROPEFFECT_COPY+DROPEFFECT_MOVE for drag and drop events between source/destination ($pdwEffect value = 3)
; ...............: Drop Effect should change depending on source/destination. Key modifiers should work the same way as Wordpads RichEdit (MS WordPad would be a RichEdit standard I assume?)
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func __RichCom_Object_GetDragDropEffect($pObject, $fDrag, $grfKeyState, $pdwEffect)
#forceref $pObject, $fDrag, $grfKeyState, $pdwEffect
If $fDrag Then ;only sent once at start of drag within same edit or between edits in script process
  ;TRUE if the query is for a IDropTarget::DragEnter or IDropTarget::DragOver. FALSE if the query is for IDropTarget::Drop.
  $hDragSource = _WinAPI_GetFocus() ;get drag source handle (only used for comparing to another AutoIt Richedit control)
  Return $_GCR_E_NOTIMPL
EndIf
If $grfKeyState = ($MK_CONTROL + $MK_ALT) Then $grfKeyState = 0 ; A Ctrl/Alt key combination does a drag copy between windows, so might as well allow for it.
Switch $grfKeyState ;= 0 or key modifier only when mouse released, now we set the drop effect
  Case 0, $MK_CONTROL, $MK_ALT
   ;_WinAPI_GetFocus() not working here, always returns source handle of 1st richedit when over 2nd richedit in same gui
   Local $tDROPEFFECT = DllStructCreate("dword", Ptr($pdwEffect))
   Local $tPoint = DllStructCreate($tagPOINT)
   Local $iOpt = Opt("MouseCoordMode", 1)
   DllStructSetData($tPoint, "x", MouseGetPos(0))
   DllStructSetData($tPoint, "y", MouseGetPos(1))
   Opt("MouseCoordMode", $iOpt)
   Local $hWnd = _WinAPI_WindowFromPoint($tPoint)
   $iMode = $DROPEFFECT_COPY ;default: $MK_LBUTTON Or $MK_RBUTTON - DD between source/destination
   If $grfKeyState = $MK_ALT Then $iMode = $DROPEFFECT_MOVE ;DD between source/destination
   If $hDragSource = $hWnd And (IsHWnd($hDragSource) + IsHWnd($hWnd)) <> 0 Then $iMode = $DROPEFFECT_COPY + $DROPEFFECT_MOVE ;DD within same edit (No key, $MK_ALT or $MK_CONTROL modifier keys)
   DllStructSetData($tDROPEFFECT, 1, $iMode)
   $hDragSource = 0 ;reset source handle (not set for a drag from an external process ($fDrag = False ))
EndSwitch
Return $_GCR_E_NOTIMPL
EndFunc   ;==>__RichCom_Object_GetDragDropEffect

Example with restored selected text after drag event

#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
#Include <GuiScrollBars.au3>
#include <ScrollBarConstants.au3>
#include <WinAPI.au3>
#include <Misc.au3>
Opt("GUIOnEventMode", 1)
Opt('MustDeclareVars', 1)
Global $iDLLUser32 = DllOpen("User32.dll"), $hRich1, $hRich2
_DualRichEdit()
Func _DualRichEdit()
Local $hForm = GUICreate("", 600, 300, -1, -1,-1 ,BitOR($WS_EX_WINDOWEDGE, $WS_EX_TOPMOST))
GUISetOnEvent($GUI_EVENT_CLOSE, "Terminate")
GUICtrlCreateLabel("First Rich Text Field", 20, 20)
GUICtrlCreateLabel("Second Rich Text Field", 300, 20)
GUICtrlCreateLabel("Enter text into the first field ... then highlight it and drag/drop it into the second field.", 20, 250, 560, -1)
GUICtrlSetFont(-1, 11, 400, -1, "Arial")
GUICtrlCreateLabel("I need the dropped text to remain in the first field ... and preferably remain highlighted.", 20, 270, 560, -1)
GUICtrlSetFont(-1, 10, 800, -1, "Arial")
$hRich1 = _GUICtrlRichEdit_Create($hForm, "", 20, 40, 200, 200, BitOR($ES_WANTRETURN, $ES_MULTILINE, $WS_VSCROLL))
_GUICtrlRichEdit_SetEventMask($hRich1, $ENM_DRAGDROPDONE)
_GUIScrollBars_ShowScrollBar($hRich1, $SB_VERT, True)
;GUICtrlSetState(-1, $GUI_DROPACCEPTED) ;does not work with UDF controls (-1 only works with native AutoIt controls)
$hRich2 = _GUICtrlRichEdit_Create($hForm, "", 300, 40, 200, 200, BitOR($ES_WANTRETURN, $ES_MULTILINE, $WS_VSCROLL))
_GUICtrlRichEdit_SetEventMask($hRich2, $ENM_DRAGDROPDONE)
_GUIScrollBars_ShowScrollBar($hRich2, $SB_VERT, True)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW)
While 1
  Sleep(50)
WEnd
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $iWparam, $iLparam)
#forceref $hWnd, $iMsg, $iWparam
Local $hWndFrom, $iCode, $tNMHDR
$tNMHDR = DllStructCreate($tagNMHDR, $iLparam)
$hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Switch __WinAPI_GetClassName($hWndFrom) ;replace with handles,
  Case $_GRE_sRTFClassName   ;if not restoring text selection on multiple richedits
   Switch $iCode
    Case $EN_DRAGDROPDONE
     If $hWndFrom <> _WinAPI_GetFocus() Then ;re-show selected text only on drag beween edits
      _GUICtrlRichEdit_HideSelection($hWndFrom, False)
     EndIf
   EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
Func __WinAPI_GetClassName($hWnd)
Local $aResult = DllCall($iDLLUser32, "int", "GetClassNameW", "hwnd", $hWnd, "wstr", "", "int", 4096)
If @error Then Return ""
Return $aResult[2]
EndFunc   ;==>__WinAPI_GetClassName
Func Terminate()
    _GUICtrlRichEdit_Destroy($hRich1)
    _GUICtrlRichEdit_Destroy($hRich2)
    Exit
EndFunc
Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites
rover

I've had enough of this forum and these people who never acknowledge posted working answers.


I see fascists...

Share this post


Link to post
Share on other sites
qwert

I'm not sure how to respond to your statement except to say: have patience. My original post was from last August. I've been working on this off and on for 6 months ... and it may take me weeks or months longer. Other issues and projects have priority over this one. Plus, your solution is involved ... not something that allows a casual response.

Those things said: I appreciate what you have provided and will work on it when I can. In the mean time, maybe others will benefit.

Share this post


Link to post
Share on other sites
lbsl

Work has already been done on the UDF by guinness and me (for #2077 and some other things), it should work in the next beta. This attachment should work for you in the interrim.

The fix allows more instances of a richedit object indeed to be shown and controlled.

It however also causes an application error after closing the AutoIT3 utility so the RichEdit controls have to be destroyed (_GUICtrlRichEdit_Destroy(ByRef $hWnd)) before exitting the program. (took me a while to figure out what the culprit was behind the error, got a -21xxxxx error code in return regarding a write error to memory)

Share this post


Link to post
Share on other sites
AdmiralAlkex

The fix allows more instances of a richedit object indeed to be shown and controlled.

It however also causes an application error after closing the AutoIT3 utility so the RichEdit controls have to be destroyed (_GUICtrlRichEdit_Destroy(ByRef $hWnd)) before exitting the program. (took me a while to figure out what the culprit was behind the error, got a -21xxxxx error code in return regarding a write error to memory)

It looks like you are supposed to destroy the RichEdit anyway, so the error is rather in your insistence to not do it after the helpfile and examples tell you to do it.

Anyway, this is off topic to this thread and I am not the expert on RichEdits. Create a new thread if this is something you want help on.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.