Page 1 of 1

Drag and drop on transparent draggable image

Posted: Thu Jun 28, 2007 4:38 pm
by Fangbeast
Thanks to Trond, NetMaestro and Srod, i've cobbled together something which I might/may use in future applications.

1. Basically, NetMaestro's blazingly fast scan region code is used to take an image either from disk or datasection and 'clip' a specified colour to the borders of the image.

2. This window (invisible) upon which the image is drawn is then drag and drop enabled for files (Like the popular internet download manager programs that all have a drag and drop target and can hide the main window)

3. The window is then checked if a drag and drop operation has been performed on it.

4. A close window event (ALT + F4) is checked so you can close it.

5. Right mouse button is checked. If up, a popup menu with one choice "Close" is displayed to close the program with the mouse.

6. If the 'close' choice is selected, program ends.


7. If the left mouse button is pushed over the image, you can drag it around the screen.

8. Window is 'sticky' (on top of all other windows)

;=============================================

Select a bunch of files and directories from Windows explorer or any other drag capable application and drop them on the image.

If a file is retrieved, debug shows you the filename.

If a directory name is retrieved (and a pb command checks this), it is sent to the search engine to be recursively listed.

A match counter keeps track of how many files were dropped.

I've put as many comments in as I could. Hope someone has a use for this. The 3 mighty wizards about helped me out endlessly.

Code: Select all

;============================================================================================================================
; Prototypes
;============================================================================================================================


;============================================================================================================================
; Visual designer created constants
;============================================================================================================================

Enumeration 1                                         ; Window constants
  #Window_draggy
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

Enumeration 1                                         ; Gadgets, menus, keyboard shortcuts
  #PopMenu_draggy_closeprog
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

Enumeration 1                                         ; Images
  #Image_draggy_dropzone
EndEnumeration

#ImageIndex = #PB_Compiler_EnumerationValue
  
Enumeration 1                                         ; Menu bars
  #PopMenu_draggy
EndEnumeration

#MenuBarIndex = #PB_Compiler_EnumerationValue

;============================================================================================================================
; Catch an image loaded from a data section
;============================================================================================================================

CatchImage(#Image_draggy_dropzone, ?_draggy_dropzone)

;============================================================================================================================
; Put all your program resources in here
;============================================================================================================================

DataSection
  _draggy_dropzone  : IncludeBinary "girl.bmp"
EndDataSection

;============================================================================================================================
; Visual designer created encapsulated window code
;============================================================================================================================


;============================================================================================================================
; ll procedural declarations
;============================================================================================================================

Declare GrabRegion(ImageID, transcolor)
Declare DropFileNames()
Declare SearchEngine(SearchDir.s)

;============================================================================================================================
; My personal constants
;============================================================================================================================

Global MatchCounter.l

Global NewList FoundDirs.s()

;============================================================================================================================
; Get the list of files dropped and deal with them
;============================================================================================================================

Procedure DropFileNames()

  NumFiles.l = CountString(EventDropFiles(), Chr(10))                          ; Check how many files were dropped.
  
  FileNames.s = EventDropFiles()                                               ; Retrieve the string of filenames
  
  If NumFiles.l                                                                ; Only do the following if there were files retrieved

    For CopyLoop = 1 To NumFiles                                               ; Loop through all items
    
      CopyItem.s = StringField(FileNames.s, CopyLoop, Chr(10))                 ; Strings are separated by Chr(10)
    
      If FileSize(CopyItem.s) = -2                                             ; If this is a directory rather than a file
      
        SearchEngine(CopyItem.s)                                               ; Pass it to the recursive search engine to expand it
        
      Else                                                                     ; Otherwise do the below
      
        MatchCounter + 1                                                        ; Keep track of how many matches you have
                
        Debug "File: " + Str(MatchCounter) + "  --  " + CopyItem.s             ; Do something with the file
        
      EndIf                                                                    ; No more tests to do
      
    Next CopyLoop                                                              ; Go through the next file in the string
    
  EndIf                                                                        ; No more tests to do
  
EndProcedure

;============================================================================================================================
; Universal, recursive search engine used by many functions
;============================================================================================================================

Procedure SearchEngine(SearchDir.s)

  ClearList(FoundDirs.s())

  If SearchDir.s <> ""

    If Right(SearchDir.s, 1) = "\"

      SearchDir.s = Left(SearchDir.s, Len(SearchDir.s) - 1)

    EndIf

    AddElement(FoundDirs.s())

    FoundDirs.s() = SearchDir.s

    Index = 0

    Repeat

      SelectElement(FoundDirs.s(), Index)

      If ExamineDirectory(0, FoundDirs.s(), "*.*")

        Path.s = FoundDirs.s() + "\"

        While NextDirectoryEntry(0)

          Filename.s = DirectoryEntryName(0)

          Select DirectoryEntryType(0)

            Case 1                                                                   ; Found a filename, do something with it
            
              MatchCounter + 1                                                        ; Keep track of how many matches you have
                
              Debug "File: " + Str(MatchCounter) + "  --  " + Path.s + Filename.s    ; Do something with the file
          
            Case 2

              Filename.s = DirectoryEntryName(0)

              If Filename.s <> ".." And Filename.s <> "."

                AddElement(FoundDirs())

                FoundDirs() = Path + Filename.s

              EndIf

          EndSelect

        Wend

      EndIf

      Index + 1

    Until Index > CountList(FoundDirs()) -1

  EndIf

EndProcedure

;============================================================================================================================
; Very fast bitmap -> region creator, By netmaestro, Contributors: eesau, nico, June 26, 2007
;============================================================================================================================

ProcedureDLL GrabRegion(ImageID, transcolor) ; HBITMAP ImageID, COLORREF transcolor

  ;=======================================================
  ;                                                      =
  ;      Very fast bitmap -> region creator              =
  ;                                                      =
  ;      By netmaestro with creative input from eesau    =
  ;                                                      =
  ;      June 26, 2007                                   =
  ;                                                      =
  ;======================================================= 
  
  Structure RGBTRIPLEC
    rgbtBlue.c
    rgbtGreen.c
    rgbtRed.c
  EndStructure

  GetObject_(ImageID, SizeOf(BITMAP), @bmp.BITMAP)
  Protected width       = bmp\bmWidth
  Protected height      = bmp\bmHeight
  Protected hVisibleRgn = CreateRectRgn_(0, 0, width, height)
  Protected tred        = Red(transcolor)
  Protected tgreen      = Green(transcolor)
  Protected tblue       = Blue(transcolor)
 
  BmiInfo.BITMAPINFOHEADER
  With BmiInfo
    \biSize         = SizeOf(BITMAPINFOHEADER)
    \biWidth        = width
    \biHeight       = -height
    \biPlanes       = 1
    \biBitCount     = 24
    \biCompression  = #BI_RGB
  EndWith   
 
  bytesperrow = 4 * ((3 * width + 3) / 4)

  *ColorBits = AllocateMemory(bytesperrow * height)
  hDC   = GetWindowDC_(#Null)
  iRes  = GetDIBits_(hDC, ImageID, 0, height, *ColorBits, @bmiInfo, #DIB_RGB_COLORS)
  ReleaseDC_(#Null, hDC)
 
  Structure_Max = (width * height * 16) + SizeOf(RGNDATAHEADER)
  *Buffer.RGNDATAHEADER = AllocateMemory(Structure_Max)
  *rd.LONG = *Buffer + SizeOf(RGNDATAHEADER)

  bufferloc = 0
  rectcount = 0
  
  For y = 0 To height - 1
    pxcount = 0
    For x = 0 To bytesperrow - 1 Step 3
      *px.RGBTRIPLEC = *ColorBits + bytesperrow * y + x
      If *px\rgbtRed = tred And *px\rgbtGreen = tgreen And *px\rgbtBlue = tblue
        transcount = 1
        firsttrans = pxcount
        While *px\rgbtRed = tred And *px\rgbtGreen = tgreen And *px\rgbtBlue = tblue And x <= bytesperrow - 4
          transcount + 1
          pxcount + 1
          x + 3     
          *px = *ColorBits + bytesperrow * y + x
        Wend
        rectcount + 1
        *rd\l = firsttrans              : *rd + 4
        *rd\l = y                       : *rd + 4
        *rd\l = firsttrans + transcount : *rd + 4
        *rd\l = y + 1                   : *rd + 4
      EndIf
      pxcount + 1
    Next
  Next
 
  With *Buffer
    \dwSize         = SizeOf(RGNDATAHEADER)
    \iType          = #RDH_RECTANGLES
    \nCount         = rectcount
    \nRgnSize       = rectcount * SizeOf(RECT)
    \rcBound\left   = 0
    \rcBound\top    = 0
    \rcBound\right  = width
    \rcBound\bottom = height
  EndWith
 
  RegionSize = SizeOf(RGNDATAHEADER) + (rectcount * SizeOf(RECT))
  hTransparentRgn = ExtCreateRegion_(#Null, RegionSize, *Buffer)
  CombineRgn_(hVisibleRgn, hVisibleRgn, hTransparentRgn, #RGN_XOR)
   
  FreeMemory(*Buffer)
  FreeMemory(*ColorBits)
  DeleteObject_(hTransparentRgn)
 
  ProcedureReturn hVisibleRgn
 
EndProcedure

;============================================================================================================================
; Mian event handling code
;============================================================================================================================

; LoadImage(#Image_draggy_dropzone, "girl.bmp")                                 ; Load from a physical file off disk manually

OpenWindow(#Window_draggy, 0 ,0, ImageWidth(#Image_draggy_dropzone), ImageHeight(#Image_draggy_dropzone), "", #PB_Window_ScreenCentered | #PB_Window_BorderLess | #PB_Window_Invisible)

SetWindowLong_(WindowID(#Window_draggy), #GWL_EXSTYLE, GetWindowLong_(WindowID(#Window_draggy), #GWL_EXSTYLE) | #WS_EX_TOOLWINDOW)

CreateGadgetList(WindowID(#Window_draggy))                                      ; Event windows without gadgets neeed a gadget list

region = GrabRegion(ImageID(#Image_draggy_dropzone), #White)                    ; Create the region for the included picture

SetWindowRgn_(WindowID(#Window_draggy), region, #True)                          ; Clip the image to the calculated region

hBrush = CreatePatternBrush_(ImageID(#Image_draggy_dropzone))                   ; Set the window background to the image.
  
SetClassLong_(WindowID(#Window_draggy), #GCL_HBRBACKGROUND, hBrush)             ; Subclass the window to allow dragging around
  
HideWindow(#Window_draggy, 0)                                                   ; Show the window now

EnableWindowDrop(#Window_draggy, #PB_Drop_Files, #PB_Drag_Copy)                 ; Enable dragging and dropping on this window

StickyWindow(#Window_draggy, 1)                                                 ; Make this window stay on top of all others

Repeat                                                                         ; Process all events
  Select WaitWindowEvent()                                                     ; Check for a window event
    Case #PB_Event_WindowDrop                                                  ; Check for files dropped on a window
      Select EventWindow()                                                     ; Which window were the files dropped on
        Case #Window_draggy                                                    ; This is the window we wanted
          Select EventDropType()                                               ; Select type type of drop event that occurred
            Case #PB_Drop_Files                   : DropFileNames()            ; Check if files were dropped?
          EndSelect                                                            ; No more checks to do
      EndSelect                                                                ; No more checks to do
    Case #PB_Event_CloseWindow                                                 ; Check for windows being closed
      Break                                                                    ; Close the program if there was one
    Case #WM_RBUTTONUP                                                         ; Check if the right mouse button is released
      CreatePopupMenu(#PopMenu_draggy)                                         ; Create a temporary popup menu over the window
        MenuItem(#PopMenu_draggy_closeprog, "Close")                           ; Add a 'close' menu item to the menu
      DisplayPopupMenu(#Window_draggy, WindowID(#Window_draggy))               ; Display the menu on that window
    Case #PB_Event_Menu                                                        ; Check if a menu event happened
      Break                                                                    ; If it did, close the program
    Case #WM_LBUTTONDOWN                                                       ; Check if the left mouse button is pressed
      SendMessage_(WindowID(#Window_draggy), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)  ; Allow the dragging of our image around
  EndSelect                                                                    ; No more checks to do
ForEver                                                                        ; Keep processing in a loop till break occurs
End                                                                            ; Make sure no program stub remains in memory
EDIT: Added the tool window style to prevent icon showing up in the task bar. Once again, it's srod who told me what to do, nothing I could have thought of by myself.

Wheeee!

Posted: Thu Jun 28, 2007 5:07 pm
by rsts
Very nice.

I just may have to increase your percentage of the royalties :D

cheers

Posted: Thu Jun 28, 2007 5:09 pm
by netmaestro
Lovely little tool, Fangs, thanks for posting. Into my toolbox it goes.

Posted: Thu Jun 28, 2007 5:13 pm
by Fangbeast
netmaestro wrote:Lovely little tool, Fangs, thanks for posting. Into my toolbox it goes.
Now that's funny!! I couldn't have made it without you, Trond and that strange fellow srod!!

Posted: Thu Jun 28, 2007 5:16 pm
by Fangbeast
rsts wrote:Very nice.

I just may have to increase your percentage of the royalties :D

cheers
I'm still waiting for the first cheque!!! Say, you don't think that NetMaestro intercepted the mail again???

/me looks suspiciously up and down the room!

Posted: Thu Jun 28, 2007 5:22 pm
by Dare
Onya Fangs.

Posted: Thu Jun 28, 2007 7:09 pm
by srod
Excellent tool. Nice one.

Posted: Fri Jun 29, 2007 3:23 am
by Fangbeast
Dare wrote:Onya Fangs.
Maaaaaaaaaaate!!!!

Posted: Fri Jun 29, 2007 3:24 am
by Fangbeast
srod wrote:Excellent tool. Nice one.
You mean, "Excellent work srod and netmaestro, we did all the hard stuff, now look what that bozo fangs did with all our hard work!!!"

Just in case...

Posted: Fri Jun 29, 2007 9:13 am
by Fangbeast
Just in case anyone doesn't get the point of this program snippet, here's a better explanation.

Unless you have a super large monitor, extra large resolution and good eyes (unlike mine) having more than one application on screen and constantly switching between them is a chore.

If the applications are somehow going to be working together, it gets even worse.

Example 1. You have written a note taker program and you want to drag text from multiple programs into it from many other programs/locations that will form a new record each time you drag to it. You can't quite see the main form of your note program to drag to it from another because they are both too large. The answer is a sticky drop target linked to your note program. Small, unobtrusive and always visible. Easier to work with.

Example 2. You have a file cataloguer. It can catalogue multiple files, search entire disks etc but sometimes you just want to add a single file and imagine having to do this multiple times from a variety of places using some arcane open file/import interface. Just for one file???? Noooooo! And once again, if the cataloguer has drag and drop ability on its' main form, trying to fit multiple programs on screen to drag and drop from them to your cataloguer. The answer once again is a sticky drop target linked to your cataloguer program. Small, unobtrusive and always visible. Easier to work with.

Thee are many situations in which the above snippet would be of great use to me personally. I have neither a large screen, high resolution or good eyesight so it will be useful to me!

Posted: Fri Jun 29, 2007 4:38 pm
by rsts
Oh.

I was trying to use it to catalog my porn and was wondering why the area I dragged it to had no affect on how it was being categorized.

Could you perhaps work up a more suitable solution? :D :D

cheers

Posted: Sat Jun 30, 2007 2:45 am
by Fangbeast
rsts, i'd suggest that if my existing solution isn't good enough for you, then you've had way too much porn, it ruined your eyesight and nothing else I write will help you.

Other symptoms would include, bad breasts, err, breath, shaking hands, an unendurable desire to lick cardboard with pictures of scanty woman on it, constant dribbling, walking in circles, the dog beginning to look attractive when there is no porn around, you fancy the postman in crotchless underwear and heels etc.

Dr Fangles' solution is to become my permanent beta tester and send me lots of money for the incredible privilege and of course, stop cataloguing porn.