Thoughts on the best way to define a 'dynamic text box'

Just starting out? Need help? Post your questions and find answers here.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Thoughts on the best way to define a 'dynamic text box'

Post by IdeasVacuum »

I have been experimenting to find a good way to present a 'Dynamic Text Box' that the User can freely re-size, edit and export as a 32bit PNG.

A short movie showing an example of one: http://www.professorcad.co.uk/pbforumquestion.html

In the movie, graphical 'handles' are displayed which the User can use to drag the Object (box graphic + multi-line text) to the desired size - that feature is not necessarily required, slider bars would be adequate, but I do need to be able to change the colour of the box and change the text font attributes.

Methods

1) 2D Sprite, using predefined image for the box

Advantages - Draw the text on the sprite, easy to output the finished result.
Disadvantages - Difficult to re-size/fit the text; Difficult to re-size the Object.

2) 2D Sprite, box graphic drawn on-the-fly

Advantages - Draw the text on the sprite; Easy to resize the sprite (replace with a re-draw); Easy to output the finished result.
Disadvantages - Difficult to re-size/fit the text; Potential for screen flicker during re-size.

3) Separate, Overlaid Windows - (Both border-less, top most has transparent background) 1 being the output for 2D drawing, the other, top window consisting of an Editor Gadget.

Advantages - Easy to resize the Object; Easy to handle box and font attribute changes.
Disadvantages - Don't know how best to handle the Z-level of the Windows so that they re-size together with a continuous display; Output the result as a screen region capture - not tested.

So, are there better methods? Would the new canvas gadget be among the contenders?
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
infratec
Always Here
Always Here
Posts: 7794
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Thoughts on the best way to define a 'dynamic text box'

Post by infratec »

Hi IdeasVacuum,

A fast try:

Code: Select all

#PickUpPixels = 10

#None = $00
#Move = $01
#ResizeLeft = $02
#ResizeRight = $04
#ResizeUp = $08
#ResizeDown = $10

OpenWindow(0, 0, 0, 640, 480, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

CanvasXPos = 10
CanvasYPos = 10
CanvasWidth = 200
CanvasHeight = 100
CanvasGadget(0, CanvasXPos, CanvasYPos, CanvasWidth, CanvasHeight)

GadgetMod = #None

Exit =#False
Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_Gadget
      If EventGadget() = 0
        Select EventType()
          Case #PB_EventType_LeftButtonDown
            StartXPos = WindowMouseX(0)
            StartYPos = WindowMouseY(0)
            If GetGadgetAttribute(0, #PB_Canvas_MouseX) > #PickUpPixels And GetGadgetAttribute(0, #PB_Canvas_MouseX) < GadgetWidth(0) - #PickUpPixels And GetGadgetAttribute(0, #PB_Canvas_MouseY) > #PickUpPixels And GetGadgetAttribute(0, #PB_Canvas_MouseY) < GadgetHeight(0) - #PickUpPixels
              GadgetMod | #Move
            Else
              If GetGadgetAttribute(0, #PB_Canvas_MouseX) < #PickUpPixels
                GadgetMod | #ResizeLeft
              ElseIf GetGadgetAttribute(0, #PB_Canvas_MouseX) > GadgetWidth(0) - #PickUpPixels
                GadgetMod | #ResizeRight
              EndIf
              If GetGadgetAttribute(0, #PB_Canvas_MouseY) < #PickUpPixels
                GadgetMod | #ResizeUp
              ElseIf GetGadgetAttribute(0, #PB_Canvas_MouseY) > GadgetHeight(0) - #PickUpPixels
                GadgetMod | #ResizeDown
              EndIf
            EndIf
          Case #PB_EventType_LeftButtonUp
            If GadgetMod <> #None
              CurrentXPos = WindowMouseX(0)
              CurrentYPos = WindowMouseY(0)
              If GadgetMod & #Move
                CanvasXPos = CanvasXPos + (CurrentXPos - StartXPos)
                CanvasYPos = CanvasYPos + (CurrentYPos - StartYPos)
              Else
                If GadgetMod & #ResizeLeft
                  CanvasXPos = CanvasXPos - (StartXPos - CurrentXPos)
                  CanvasWidth = CanvasWidth + (StartXPos - CurrentXPos)
                ElseIf GadgetMod & #ResizeRight
                  CanvasWidth + CurrentXPos - StartXPos
                EndIf
                If GadgetMod & #ResizeUp
                  CanvasYPos = CanvasYPos - (StartYPos - CurrentYPos)
                  CanvasHeight = CanvasHeight + (StartYPos - CurrentYPos)
                ElseIf GadgetMod & #ResizeDown
                  CanvasHeight + CurrentYPos - StartYPos
                EndIf
              EndIf
              CanvasGadget(0, CanvasXPos, CanvasYPos, CanvasWidth, CanvasHeight)
              GadgetMod = #None
            EndIf
        EndSelect
      EndIf
    Case #PB_Event_CloseWindow
      Exit = #True
  EndSelect
Until Exit
Maybe it makes your decision easier. :mrgreen:

Bernd
User avatar
kenmo
Addict
Addict
Posts: 2081
Joined: Tue Dec 23, 2003 3:54 am

Re: Thoughts on the best way to define a 'dynamic text box'

Post by kenmo »

CanvasGadget was my first instinct too... it's great for drawing interactive objects. I think it's quite flicker-free as well?
infratec
Always Here
Always Here
Posts: 7794
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Thoughts on the best way to define a 'dynamic text box'

Post by infratec »

But I found a problem:

Code: Select all

#PickUpPixels = 10

#None = $00
#Move = $01
#ResizeLeft = $02
#ResizeRight = $04
#ResizeUp = $08
#ResizeDown = $10

Structure GadgetStr
  No.i
  Mod.i
  XPos.i
  YPos.i
  Width.i
  Height.i
EndStructure

NewMap GadgetMap.GadgetStr()


OpenWindow(0, 0, 0, 640, 480, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

AddMapElement(GadgetMap(), "0")
GadgetMap()\No = 0
GadgetMap()\XPos = 10
GadgetMap()\YPos = 10
GadgetMap()\Width = 200
GadgetMap()\Height = 100
CanvasGadget(0, GadgetMap()\XPos, GadgetMap()\YPos, GadgetMap()\Width, GadgetMap()\Height, #PB_Canvas_Border)

AddMapElement(GadgetMap(), "1")
GadgetMap()\No = 1
GadgetMap()\XPos = 10
GadgetMap()\YPos = 200
GadgetMap()\Width = 200
GadgetMap()\Height = 100
CanvasGadget(1, GadgetMap()\XPos, GadgetMap()\YPos, GadgetMap()\Width, GadgetMap()\Height, #PB_Canvas_Border)

GadgetMod = #None

Exit =#False
Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_Gadget
      EventGadget = EventGadget()
      If FindMapElement(GadgetMap(), Str(EventGadget))
        Select EventType()
          Case #PB_EventType_LeftButtonDown
            StartXPos = WindowMouseX(0)
            StartYPos = WindowMouseY(0)
            If GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseX) > #PickUpPixels And GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseX) < GadgetWidth(GadgetMap()\No) - #PickUpPixels And GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseY) > #PickUpPixels And GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseY) < GadgetHeight(GadgetMap()\No) - #PickUpPixels
              GadgetMap()\Mod | #Move
            Else
              If GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseX) < #PickUpPixels
                GadgetMap()\Mod | #ResizeLeft
              ElseIf GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseX) > GadgetWidth(GadgetMap()\No) - #PickUpPixels
                GadgetMap()\Mod | #ResizeRight
              EndIf
              If GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseY) < #PickUpPixels
                GadgetMap()\Mod | #ResizeUp
              ElseIf GetGadgetAttribute(GadgetMap()\No, #PB_Canvas_MouseY) > GadgetHeight(GadgetMap()\No) - #PickUpPixels
                GadgetMap()\Mod | #ResizeDown
              EndIf
            EndIf
          Case #PB_EventType_LeftButtonUp 
            If GadgetMap()\Mod <> #None
              CurrentXPos = WindowMouseX(0)
              CurrentYPos = WindowMouseY(0)
              If GadgetMap()\Mod & #Move
                GadgetMap()\XPos = GadgetMap()\XPos + (CurrentXPos - StartXPos)
                GadgetMap()\YPos = GadgetMap()\YPos + (CurrentYPos - StartYPos)
              Else
                If GadgetMap()\Mod & #ResizeLeft
                  GadgetMap()\XPos = GadgetMap()\XPos - (StartXPos - CurrentXPos)
                  GadgetMap()\Width = GadgetMap()\Width + (StartXPos - CurrentXPos)
                ElseIf GadgetMap()\Mod & #ResizeRight
                  GadgetMap()\Width + CurrentXPos - StartXPos
                EndIf
                If GadgetMap()\Mod & #ResizeUp
                  GadgetMap()\YPos = GadgetMap()\YPos - (StartYPos - CurrentYPos)
                  GadgetMap()\Height = GadgetMap()\Height + (StartYPos - CurrentYPos)
                ElseIf GadgetMap()\Mod & #ResizeDown
                  GadgetMap()\Height + CurrentYPos - StartYPos
                EndIf
              EndIf
              CanvasGadget(GadgetMap()\No, GadgetMap()\XPos, GadgetMap()\YPos, GadgetMap()\Width, GadgetMap()\Height, #PB_Canvas_Border)
              GadgetMap()\Mod = #None
            EndIf
        EndSelect
      EndIf
    Case #PB_Event_CloseWindow
      Exit = #True
  EndSelect
Until Exit
If you move them that they are overlapping, you can not select the right Gadget for resize :cry:

Bernd
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Thoughts on the best way to define a 'dynamic text box'

Post by IdeasVacuum »

Interesting infratec, I didn't think about using the canvas itself as part of the Object. Learnt a lot from your code. Overlapping would never be a problem because there would only ever be one Object at a time. However, I think the canvas can only be rectangular/square, so as-is it will not meet the requirements.

Another possibility would be to have an Editor gadget on top of an image gadget - officially, that is not recommended, but I have 'got away with it' in the past with the image gadget disabled once loaded.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Thoughts on the best way to define a 'dynamic text box'

Post by IdeasVacuum »

This is (less) rubbish (now), but I think it shows that the Canvas Gadget could be the solution. The code is stripped-out of the PB help example:

Code: Select all

Enumeration
#IMAGE_Content  ; stores the previous CanvasGadget content while the mouse is down
#IMAGE_Color
#IMAGE_LoadSave
#ImageSave
#DynText
#Editor
#Canvas
#Color
#Refresh
#Shadow
#Ctr
#Lft
#Rgt
#Clear
#Load
#Save
#TextEditor
EndEnumeration

Global igCurrentColour.i, igStartX.i, igStartY.i, igEndX.i, igEndY.i
Global igLastStartX.i, igLastStartY.i, igLastEndX.i, igLastEndY.i
Global gsrcDC.l, igDeskX.i, igDeskY.i, igLastDeskX.i, igLastDeskY.i
Global sgImageOutFile.s = ""
Global igObjectExists.i = #False
;Editor Font
Global   sgFontName.s = "Arial"
Global   igFontSize.i = 16
Global igFontColour.i = RGB(0,0,0)
Global  igFontStyle.i = (#PB_Font_Bold | #PB_Font_HighQuality + 2)
Global    igFontID1.i = LoadFont(1, sgFontName, igFontSize, igFontStyle)
Global     igShadow.i = #False
Global       sgText.s = "Mary had a little lamb, it's fleece was white as snow. Everywhere that Mary went, the lamb was sure to go."

UsePNGImageDecoder()
UsePNGImageEncoder()

          ;CreateImage(#IMAGE_Content, 380, 380,32|#PB_Image_Transparent)
          CreateImage(#IMAGE_Content, 380, 380, 24)

          ;Colour Selection Button

          igCurrentColour = RGB(191,223,255)
          CreateImage(#IMAGE_Color, 40, 15, 24)

          If StartDrawing(ImageOutput(#IMAGE_Color))
                  Box(0, 0, 40, 15, igCurrentColour)
                  StopDrawing()
          EndIf

Procedure SetAlignment(iJustify, iX, iY)
;--------------------------------------

  Protected sText.s
            sText = GetGadgetText(#TextEditor)
              FreeGadget(#TextEditor)
            EditorGadget(#TextEditor, igStartX + 25, igStartY + 25, (iX-igStartX) - 30, (iY-igStartY) - 30, iJustify)
   SendMessage_(GadgetID(#TextEditor),#EM_SETTARGETDEVICE,#Null,0) ;WordWrap on
          SetGadgetColor(#TextEditor,#PB_Gadget_BackColor,igCurrentColour)
           SetGadgetFont(#TextEditor,igFontID1)
           SetGadgetText(#TextEditor, sText)

EndProcedure

Procedure.l CaptureRegion(iX.i, iY.i, iW.i, iH.i)
;------------------------------------------------

Shared gsrcDC
   dm.DEVMODE

       gsrcDC = CreateDC_("DISPLAY","","",dm)
      trgDC.l = CreateCompatibleDC_(gsrcDC)
  BMPHandle.l = CreateCompatibleBitmap_(gsrcDC,iW,iH)

  SelectObject_(trgDC,BMPHandle)
        BitBlt_(trgDC,0,0,iW,iH,gsrcDC,iX,iY,#SRCCOPY)
      DeleteDC_(trgDC)
     ReleaseDC_(BMPHandle,srcDC)

  ProcedureReturn BMPHandle

EndProcedure

Procedure ImageSave()
;--------------------

Protected iX.i = (igLastDeskX - 5)
Protected iY.i = (igLastDeskY - 5)
Protected iW.i = (igLastEndX - igLastStartX) + 10
Protected iH.i = (igLastEndY - igLastStartY) + 10

  If(igShadow = #True) : iW + 4 : iH + 4 : EndIf

     ScreenCaptureAddress = CaptureRegion(iX,iY,iW,iH)
  If ScreenCaptureAddress <> 0

           ;CreateImage(#ImageSave,iW,iH,32|#PB_Image_Transparent)
            CreateImage(#ImageSave,iW,iH,24)
           StartDrawing(ImageOutput(#ImageSave))
              DrawImage(ScreenCaptureAddress,0,0)
            StopDrawing()
              SaveImage(#ImageSave,sgImageOutFile,#PB_ImagePlugin_PNG)

              FreeImage(#ImageSave)
              DeleteDC_(gsrcDC)
          DeleteObject_(ScreenCaptureAddress)
  Else
          MessageRequester("Image Save Failed", "Cannot save file: " + sgImageOutFile)
  EndIf

EndProcedure

Procedure DrawObject(x,y)
;------------------------

        Shared igObjectExists, igCurrentColour, igStartX, igStartY, igLastStartX, igLastStartY, igLastEndX, igLastEndY, igDeskX, igDeskY

        If StartDrawing(CanvasOutput(#Canvas))

                   DrawImage(ImageID(#IMAGE_Content), 0, 0)

                   ;Shadow
                    If(igShadow = #True)

                    RoundBox(igStartX + 4, igStartY + 4, (x-igStartX), (y-igStartY), 12, 12, RGB(128,128,128))
                    EndIf

                   ;Outline
                    RoundBox(igStartX, igStartY, x-igStartX, y-igStartY, 14, 14, RGB(0,0,0))

                   ;Fill
                    RoundBox(igStartX + 2, igStartY + 2, (x-igStartX) - 4, (y-igStartY) - 4, 12, 12, igCurrentColour)


              SetGadgetColor(#TextEditor,#PB_Gadget_BackColor,igCurrentColour)
               SetGadgetFont(#TextEditor,igFontID1)
                ResizeGadget(#TextEditor,igStartX + 25, igStartY + 25, (x-igStartX) - 30, (y-igStartY) - 30)
               SetGadgetText(#TextEditor,sgText)

                 DrawingMode(#PB_2DDrawing_Default)
                 StopDrawing()

                 igLastStartX = igStartX
                 igLastStartY = igStartY
                  igLastDeskX = igDeskX
                  igLastDeskY = igDeskY
                   igLastEndX = x
                   igLastEndY = y
               igObjectExists = #True
        EndIf

EndProcedure

Procedure OpenWin()
;------------------

        If OpenWindow(#DynText,0,0,460,400,"Dynamic Caption Box",#PB_Window_Invisible|#PB_Window_SystemMenu|#PB_Window_ScreenCentered)

                       CanvasGadget(#Canvas, 10, 10, 380, 380, #PB_Canvas_ClipMouse)

                  ButtonImageGadget(#Color,  400,  10, 50, 25, ImageID(#IMAGE_Color))
                       ButtonGadget(#Refresh,400,  40, 50, 25, "Refresh")

                       ButtonGadget(#Shadow, 400,  80, 50, 25, "Shadow")
                       ButtonGadget(#Ctr,    400, 125, 50, 25, "Ctr Just")
                       ButtonGadget(#Lft,    400, 150, 50, 25, "Lft Just")
                       ButtonGadget(#Rgt,    400, 175, 50, 25, "Rgt Just")

                       ButtonGadget(#Clear,  400, 280, 50, 25, "Clear")
                       ButtonGadget(#Load,   400, 335, 50, 25, "Load")
                       ButtonGadget(#Save,   400, 365, 50, 25, "Save")

                       EditorGadget(#TextEditor,10,10,380,380,#ES_CENTER)

                       SendMessage_(GadgetID(#TextEditor),#EM_SETTARGETDEVICE,#Null,0) ;WordWrap on

                 SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor,#PB_Cursor_Default)
                         HideWindow(#DynText,#False)

        EndIf

EndProcedure

Procedure WaitForUser()
;----------------------
  Shared igObjectExists
  Repeat
       iEvent = WaitWindowEvent()
    If iEvent = #PB_Event_Gadget

                  iEventGadget = EventGadget()
           Select iEventGadget

             Case #Canvas
                     igEndX = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseX)
                     igEndY = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseY)

                     Select EventType()

                               Case #PB_EventType_LeftButtonDown
                                 ;
                                 ; This stores the current content of the CanvasGadget in #IMAGE_Content,
                                 ; so it can be re-drawn while the mouse moves
                                 ;
                                 If StartDrawing(ImageOutput(#IMAGE_Content))
                                          DrawImage(GetGadgetAttribute(#Canvas, #PB_Canvas_Image), 0, 0)
                                        StopDrawing()
                                 EndIf

                                  igDeskX = DesktopMouseX()
                                  igDeskY = DesktopMouseY()
                                 igStartX = igEndX
                                 igStartY = igEndY
                                 DrawObject(igEndX, igEndY)

                               Case #PB_EventType_LeftButtonUp
                                 DrawObject(igEndX, igEndY)

                               Case #PB_EventType_MouseMove
                                 If GetGadgetAttribute(#Canvas, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton
                                   DrawObject(igEndX, igEndY)
                                 EndIf
                     EndSelect

             Case #Color
                     igCurrentColour = ColorRequester(igCurrentColour)
                     If StartDrawing(ImageOutput(#IMAGE_Color))
                                          Box(0, 0, 40, 15, igCurrentColour)
                                  StopDrawing()
                           SetGadgetAttribute(#Color, #PB_Button_Image, ImageID(#IMAGE_Color))
                     EndIf

             Case #Shadow
                     If(igShadow = #False)
                                igShadow = #True
                     Else
                                igShadow = #False
                     EndIf

                     If(igObjectExists = #True)

                              igStartX = igLastStartX
                              igStartY = igLastStartY
                              DrawObject(igLastEndX,igLastEndY)
                     EndIf

             Case #Refresh
                     igStartX = igLastStartX
                     igStartY = igLastStartY
                     DrawObject(igLastEndX,igLastEndY)

             Case #Ctr
                     igStartX = igLastStartX
                     igStartY = igLastStartY
                     SetAlignment(#ES_CENTER, igLastEndX, igLastEndY)

             Case #Lft
                     igStartX = igLastStartX
                     igStartY = igLastStartY
                     SetAlignment(#ES_LEFT, igLastEndX, igLastEndY)

             Case #Rgt
                     igStartX = igLastStartX
                     igStartY = igLastStartY
                     SetAlignment(#ES_RIGHT, igLastEndX, igLastEndY)

             Case #Clear
                     If StartDrawing(CanvasOutput(#Canvas))
                       Box(0, 0, 380, 380, $FFFFFF)
                       StopDrawing()
                     EndIf

                     igObjectExists = #False

             Case #Load
                        File$ = OpenFileRequester("Load Image...", "", "PNG Images|*.png|All Files|*.*", 0)
                     If File$

                              If LoadImage(#IMAGE_LoadSave, File$)

                                    If StartDrawing(CanvasOutput(#Canvas))

                                           Box(0, 0, 380, 380, $FFFFFF)
                                           DrawImage(ImageID(#IMAGE_LoadSave), 0, 0)
                                           StopDrawing()
                                    EndIf

                                    FreeImage(#IMAGE_LoadSave)
                              Else

                                    MessageRequester("Image File", "Cannot load image: " + File$)
                              EndIf
                     EndIf

             Case #Save
                        sgImageOutFile = SaveFileRequester("Save Image", sgImageOutFile, "PNG Images|*.png|All Files|*.*", 0)
                     If sgImageOutFile And (FileSize(sgImageOutFile) = -1 Or MessageRequester("File Exists", "Overwrite this file? " + sgImageOutFile, #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes)

                            ImageSave()
                     EndIf

           EndSelect

    EndIf

  Until iEvent = #PB_Event_CloseWindow

EndProcedure

OpenWin()
WaitForUser()
End
Snag with the editor gadget is the scrollbars showing-up. Is there a way to suppress them?

Edit: Slightly refined to be less rubbish :)
Edit2: Further refinement, plus extra issues!
Edit3: Changed to Kiffy's text alignment method.

New question: I'm saving the Object out as a PNG. As it is an irregular shape, the image has to include some of the background. The apps receiving the image need the background to be transparent. I can set 32bits during image create, but since the save is done via screen capture, the image is actually 24bit. Is there a way to identify the (white) background as being the transparency region so that it is saved as such in a PNG? This is something that image viewers such as IrfanView can accomplish with 24bit images (but with User input)

Edit: Answer: Create a 32bit Image for the screen capture. Before saving, set DrawingMode(#PB_2DDrawing_AlphaChannel), then Fill the background with the colour representing transparency: FillArea(0, 0, igBorderColour, igTransparent) [igTransparent = RGBA(0,0,0,0)]
Last edited by IdeasVacuum on Tue Nov 22, 2011 1:20 am, edited 5 times in total.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Thoughts on the best way to define a 'dynamic text box'

Post by IdeasVacuum »

Oh-oh, when I do a screen capture (BitBlt), the capture is perfect......... but only the graphic is there, the text is missing :shock:

I'm thinking that might be a z-level issue, but how to promote an Editor Gadget to topmost Z?

Edit: Kiffy's text justification enhancement seems to have fixed this problem. Code in 1st post updated again.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Post Reply