Custom StringGadget with Image button [CrossPlatform]

Share your advanced PureBasic knowledge/code with the community.
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

Another gadget with canvas, now string gadget.
I really love to have a string gadget with some image button in it like stringgadget in windows 10 and web browsers. so i try and create it with canvas gadget.

I must say my thx to STARGÅTE for http://www.purebasic.fr/german/viewtopi ... 85#p297285 that helps me so much.

please test it and report any bug or any future u want to be added.

Image

see example :
http://purebasic.fr/english/viewtopic.p ... 80#p496080

Enjoy,
Peyman.

Code: Select all

; ====================================
; Name:             StringGadgetEx
; Version:          1.35
; Author:           Peyman
; Created:          22th Oct 2016
; Update:           04th Nov 2016
; OS:               All
; Compiler Option : ThreadSafe
; PB ver.:          5.20+
; License:          Free
;
; Thanks :          
;                   STARGÅTE - For a nice code on creating a StringGadget With CanvasGadget
;                   kenmo - for show DrawText_ api have better result in windows
;                   And all of you that use it and send good comments
;
; ====================================
;{ Release info...
; 1.00 First release version
;
; 1.10 Changed #StringGadgetEx_FontID to #StringGadgetEx_Font
;      Fixed a problem in event system
;      Fixed some problem in drawing Text with GapY param
;      Fixed problem with hilighiting text when gadget dont have focus
;      Fixed a bug in FreeStringGadgetEx that cause crash
;      Added Font in example
;      Added double left click for selecting texts
;
; 1.20 Added CTRL + X, CTRL + C, CTRL + V for cut, copy and paste texts
;      Added Triple Left Click for selecting all text of StringGadgetEx
;
; 1.21 Fixed problem in CTRL + V for numeric, lowercase and uppercase gadgets
;
; 1.22 Changed CTRL + * to Command + * in mac os
;
; 1.24 Changed cursor position after right and left key pressed when text selected
;      Fixed a bug in mac for command + *
;      Added ResizeStringGadgetEx
;
; 1.30 Changed all StringGadgetEx_ procedures to SGEx_*
;      Changed all StringGadgetEx_ constants to SGEx_*
;      Changed GetText parameters, now it can get part of text
;      Changed Password character in unicode mode to Black Circle instead of asterisk
;      Changed Callback system now each gadget can have many callbacks
;      Removed SGEx_SetAttribute (all attributes now is in command)
;      Removed SGEx_SetData and SGEx_GetData (integrated in command)
;      Added Command procedure
;      Added UnbindEvent procedure
;      Added so many commands, see in command enumeration
;      Added #SGEx_CursorColor and #SGEx_DefaultTextColor attribute
;      Added InsertText procedure
;      Added focus, lostfocus and right click event
;      Fixed a bug in button click event
;      Fixed a bug in GetMousePosition for password gadgets
;
; 1.31 Used DrawText_ api instead of PB DrawText in windows (thx kenmo for writing code)
;
; 1.32 Fixed Tab and Shift + Tab in linux and mac with AGF module
;
; 1.35 Added AutoComplete future
;      Added #SGEx_Command_AutoCompleteColor in commands
;
;}


;- Read About AGF module
;  this gadget have problem in linux and mac with TAB and SHIFT + TAB key for jump from current gadget
;  to another gadget so mk-soft find a way to handle this, maybe its not perfect and unofficial but for
;  now its better than nothing. if you include AGF module here, StringGadgetEx module automatically use
;  it on mac and linux os and if yo dont like it just ignore it, so for those want to include it you just
;  must Import it here As XIncludeFile Or copy paste code:
; XIncludeFile "AGF.pbi"


;- START OF MODULE
DeclareModule StringGadgetEx
  ; Flags
CompilerIf #PB_Compiler_Version >= 540
  EnumerationBinary
    #SGEx_BorderLess
    #SGEx_ColoredBorder
    #SGEx_Numeric
    #SGEx_LowerCase
    #SGEx_UpperCase
    #SGEx_Password
  EndEnumeration
CompilerElse
  Enumeration
    #SGEx_BorderLess    = 1
    #SGEx_ColoredBorder = 2
    #SGEx_Numeric       = 4
    #SGEx_LowerCase     = 8
    #SGEx_UpperCase     = 16
    #SGEx_Password      = 32
  EndEnumeration
CompilerEndIf

  ; Buttons
  Enumeration 
    #SGEx_Left_Button
    #SGEx_Right_Button
  EndEnumeration
  
  ; Events
CompilerIf #PB_Compiler_Version >= 540
  EnumerationBinary
    #SGEx_Event_ButtonClick
    #SGEx_Event_RightClick
    #SGEx_Event_Input
    #SGEx_Event_Key
    #SGEx_Event_Focus
    #SGEx_Event_LostFocus
  EndEnumeration
CompilerElse
  Enumeration
    #SGEx_Event_ButtonClick = 1
    #SGEx_Event_RightClick  = 2
    #SGEx_Event_Input       = 4
    #SGEx_Event_Key         = 8
    #SGEx_Event_Focus       = 16
    #SGEx_Event_LostFocus   = 32
  EndEnumeration
CompilerEndIf

  ; Commands
  Enumeration 1
    #SGEx_Command_ClearSelection
    #SGEx_Command_SetSelection
    #SGEx_Command_DeleteSelection
    #SGEx_Command_GetSelectionStart
    #SGEx_Command_GetSelectionEnd
    #SGEx_Command_SelectionLength
    
    #SGEx_Command_Length
    
    #SGEx_Command_Copy
    #SGEx_Command_Cut
    #SGEx_Command_Paste
    
    #SGEx_Command_ActiveColor
    #SGEx_Command_InActiveColor
    #SGEx_Command_BorderSize
    #SGEx_Command_BackColor
    #SGEx_Command_FrontColor
    #SGEx_Command_DefaultTextColor
    #SGEx_Command_HilightColor
    #SGEx_Command_AutoCompleteColor
    
    #SGEx_Command_CursorColor
    #SGEx_Command_CursorBlinkingTime
    
    #SGEx_Command_Font
    
    #SGEx_Command_GapX
    #SGEx_Command_GapY
    
    #SGEx_Command_UserData
  EndEnumeration
  
  
  Structure SGEx_EventHelper
    Event.b
    Gadget.i
    Button.i
    Input.s
    key.i
  EndStructure
  
  ;- Public
  Declare SGEx_Create(Gadget, X, Y, Width, Height, Content$, DefaultString$ = #Null$, Flags.w = #Null)
  Declare SGEx_Free(Gadget)
  Declare SGEx_AddButton(Gadget, ButtonID, Image, Flag.b)
  Declare SGEx_RemoveButton(Gadget, ButtonID)
  Declare SGEx_SetText(Gadget, Text$)
  Declare.s SGEx_GetText(Gadget, StartPos = #PB_Ignore, EndPos = #PB_Ignore)
  Declare SGEx_InsertText(Gadget, Text$)
  Declare SGEx_BindEvent(Gadget, *Callback, EventType = #PB_All)
  Declare SGEx_UnbindEvent(Gadget, *Callback, EventType = #PB_All)
  Declare SGEx_Resize(Gadget, X = #PB_Ignore, Y = #PB_Ignore, Width = #PB_Ignore, Height = #PB_Ignore)
  Declare SGEx_Command(Gadget, Command, Param = #PB_Ignore, lParam = #PB_Ignore)
  Declare SGEx_AddACText(Gadget, Text$, NoCase.b = #False, Seprator$ = " ")
  Declare SGEx_RemoveACText(Gadget, Text$, Seprator$ = " ")
EndDeclareModule


Module StringGadgetEx
  EnableExplicit
  
  CompilerIf #PB_Compiler_Thread = #False
    CompilerError "ThreadSafe option must be enabled in Compiler Option"
  CompilerEndIf
  
  CompilerIf Not Defined(White, #PB_Constant)
    #White = $FFFFFF
  CompilerEndIf
  
  CompilerIf Not Defined(Black, #PB_Constant)
    #Black = 0
  CompilerEndIf
  
  CompilerIf Not Defined(Blue, #PB_Constant)
    #Blue = $FF0000
  CompilerEndIf
  
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    #SGEx_Control_Key = #PB_Canvas_Command
  CompilerElse
    #SGEx_Control_Key = #PB_Canvas_Control
  CompilerEndIf
  
  CompilerIf #PB_Compiler_Unicode
    #Password_Char$ = Chr($25CF)
  CompilerElse
    #Password_Char$ = "*"
  CompilerEndIf
  
  Enumeration #PB_EventType_FirstCustomValue
    #SGEx_EventType_Blink
  EndEnumeration
  
  CompilerIf #PB_Compiler_OS <> #PB_OS_Windows And Defined(AGF, #PB_Module)
    #Use_Internal_Tab = #True
  CompilerElse
    #Use_Internal_Tab = #False
  CompilerEndIf
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    #TabKey_While_Shift_Pressed = 65056
  CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
    #TabKey_While_Shift_Pressed = 25
  CompilerEndIf
  
  Prototype Callback(*Event)
  
  Structure Buttons_desc
    Image.l
    Button.l
    Flag.b
  EndStructure
  
  Structure Callback_desc
    *Callback
    CEvents.b
  EndStructure
  
  Structure ACTexts_desc
    Text.s
    NoCase.b
  EndStructure
  
  Structure StringGadgetEx_desc
    Gadget.l
    *_Data
    
    List Buttons.Buttons_desc()
    LButtonsWidth.l
    RButtonsWidth.l
    
    List Callbacks.Callback_desc()
    Event.SGEx_EventHelper
    
    List ACTexts.ACTexts_desc()
    ACColor.l
    
    Flags.w
    
    hasFocus.b
    String.s
    DefaultString.s
    
    TextPos.i
    
    hTread.i
    BlinkingTime.w
    Blink.b
    
    GapX.b
    GapY.b
    
    CursorPosition.i
    FixCursorPosition.i
    CursorLength.i
    
    Selected.b
    
    TripleTime.i
    
    Fontid.i
    Border_Size.b
    Back_Color.l
    Front_Color.l
    DefaultTextColor.l
    HilightColor.l
    CursorColor.l
    Active_Color.l
    InActive_Color.l
  EndStructure
  
  ;- Internal Procedures
  Procedure ContrastColor(iColor)
    Protected luma.d
    ;  Counting the perceptive luminance (aka luma) - human eye favors green color... 
    luma  = (0.299 * Red(iColor) + 0.587 * Green(iColor) + 0.114 * Blue(iColor)) / 255
  
      ; Return black For bright colors, white For dark colors
    If luma > 0.5
      ProcedureReturn #Black
    Else
      ProcedureReturn #White
    EndIf
  EndProcedure
  
  
  Procedure IsInRegion(x, y, width, height, xcur, ycur)
    If xcur >= x And xcur <= x + width
      If ycur >= y And ycur <= y + height
        ProcedureReturn #True
      EndIf
    EndIf
  EndProcedure
  
  
  Procedure DispatchEvents(*buff.StringGadgetEx_desc, Event)
    Protected Callback.Callback
    
    With *buff
      ForEach \Callbacks()
        If \Callbacks()\CEvents & Event
          Callback = \Callbacks()\Callback
          \Event\Event = Event
          Callback(\Event)
        EndIf
      Next
    EndWith
  EndProcedure
  
  
  Procedure CalcButonsWidth(*buff.StringGadgetEx_desc, Left = #True)
    Protected width
    
    With *buff
      ForEach \Buttons()
        If Left
          If \Buttons()\Flag = #SGEx_Left_Button
            width + ImageWidth(\Buttons()\Image)
          EndIf
        Else
          If \Buttons()\Flag = #SGEx_Right_Button
            width + ImageWidth(\Buttons()\Image)
          EndIf
        EndIf
      Next
    EndWith
    
    ProcedureReturn width
  EndProcedure
  
  
  Procedure CheckButtonClick(*buff.StringGadgetEx_desc)
    Protected Button = -1, X, Y, LX, RX, TmpX
    
    With *buff
      X = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX)
      Y = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY)
      RX = GadgetWidth(\Gadget)
      
      ForEach \Buttons()
        If \Buttons()\Flag = #SGEx_Right_Button
          RX - ImageWidth(\Buttons()\Image)
          If IsInRegion(RX, 0, ImageWidth(\Buttons()\Image), ImageHeight(\Buttons()\Image), X, Y)
            Button = \Buttons()\Button
            Break
          EndIf
        Else
          If IsInRegion(LX, 0, ImageWidth(\Buttons()\Image), ImageHeight(\Buttons()\Image), X, Y)
            Button = \Buttons()\Button
            Break
          EndIf
          LX + ImageWidth(\Buttons()\Image)
        EndIf
      Next
    EndWith
    
    ProcedureReturn Button
  EndProcedure
  
  
  Procedure ChangeMouseCursor(*buff.StringGadgetEx_desc)
    Protected GapX, GapY, X, Y
    
    With *buff
      GapX = \GapX + \Border_Size + \LButtonsWidth
      GapY = \Border_Size
      If \GapY > -1
        GapY + \GapY
      EndIf
      
      X = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX)
      Y = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY)
      
      If IsInRegion(GapX, GapY, GadgetWidth(\Gadget) - GapX - \RButtonsWidth - \Border_Size, GadgetHeight(\Gadget) - \Border_Size * 2, X, Y)
        SetGadgetAttribute(\Gadget, #PB_Canvas_Cursor, #PB_Cursor_IBeam)
      Else
        SetGadgetAttribute(\Gadget, #PB_Canvas_Cursor, #PB_Cursor_Default)
      EndIf
      
    EndWith
  EndProcedure
  
  
  
  
  Procedure DrawingText(X, Y, Text$, FrontColor, BackColor, hDC, FontID)    
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected WinRect.RECT
      
      If FontID
        SelectObject_(hDC, FontID)
      Else
        SelectObject_(hDC, GetGadgetFont(#PB_Default))
      EndIf
        
      With WinRect
        \left = X
        \top = Y
        \right = OutputWidth()
        \bottom = OutputHeight()
      EndWith
        
      SetTextColor_(hDC, FrontColor)
      SetBkColor_(hDC, BackColor)
      DrawText_(hDC, Text$, -1, WinRect, #DT_SINGLELINE | #DT_NOPREFIX)
    CompilerElse
      DrawText(X, Y, Text$, FrontColor, BackColor)
    CompilerEndIf
  EndProcedure
  
  
  Procedure UpdateStringGadgetEx(*buff.StringGadgetEx_desc, On = #PB_Ignore)
    Protected index, color, String$, HilightString$, HilightPosition
    Protected GapX, GapY, Area, LeftImgwidth, RightImgwidth, hDC
    Protected NewList Buttons.Buttons_desc()
    
    With *buff
      If On = #True
        \Blink = #True
      ElseIf On = #False
        \Blink = #False
      Else
        If \hasFocus
          \Blink = #True - \Blink
        EndIf
      EndIf
      
      hDC = StartDrawing(CanvasOutput(\Gadget))
        Box(0, 0, OutputWidth(), OutputHeight(), \Back_Color)
        
        If \Fontid
          DrawingFont(\Fontid)
        Else
          DrawingFont(#PB_Default)
        EndIf
        
        GapX = \Border_Size + \GapX + \LButtonsWidth
        If \GapY > -1
          GapY = \GapY + \Border_Size
        Else
          GapY = Round((OutputHeight() - \Border_Size * 2 - TextHeight("A")) / 2, #PB_Round_Nearest)
        EndIf
        
        If \String
          If \Flags & #SGEx_Password
            For index = 1 To Len(\String)
              String$ + #Password_Char$
            Next
          Else
            String$ = \String
          EndIf
        Else
          DrawingText(GapX, GapY, \DefaultString, \DefaultTextColor, \Back_Color, hDC, \Fontid)
        EndIf
        
        If \CursorPosition = 0
          \TextPos = 0
        Else
          Area = OutputWidth() - GapX - \RButtonsWidth - \Border_Size
          
          If TextWidth(Left(String$, \CursorPosition)) >= Area
            If TextWidth(Left(String$, \CursorPosition)) - Area > \TextPos
              \TextPos = TextWidth(Left(String$, \CursorPosition)) - Area
            EndIf
          EndIf
          
          If GapX - \TextPos + TextWidth(Left(String$, \CursorPosition)) < GapX
            \TextPos - TextWidth(Mid(String$, \CursorPosition - 10, 10))
            If \TextPos < 0
              \TextPos = 0
            EndIf
          EndIf
        EndIf
        
        If ListIndex(\ACTexts()) = -1 Or \Flags & #SGEx_Password
          If \CursorLength <> 0 And \hasFocus
            If \CursorLength < 0
              HilightString$ = Mid(String$, \FixCursorPosition + 1, Abs(\CursorLength))
              HilightPosition = \FixCursorPosition + 1
            Else
              HilightString$ = Mid(String$, \CursorPosition + 1, \CursorLength)
              HilightPosition = \CursorPosition + 1
            EndIf
            
            DrawingText(GapX - \TextPos, GapY, Left(String$, HilightPosition - 1), \Front_Color, \Back_Color, hDC, \Fontid)
            DrawingText(GapX - \TextPos + TextWidth(Left(String$, HilightPosition - 1)), GapY, HilightString$, ContrastColor(\HilightColor), \HilightColor, hDC, \Fontid)
            DrawingText(GapX - \TextPos + TextWidth(Left(String$, HilightPosition - 1)) + TextWidth(HilightString$), GapY, Mid(String$, HilightPosition + Len(HilightString$)), \Front_Color, \Back_Color, hDC, \Fontid)
          Else
            DrawingText(GapX - \TextPos, GapY, String$, \Front_Color, \Back_Color, hDC, \Fontid)
          EndIf
        Else
          HilightString$ = Mid(\ACTexts()\Text, Len(String$) + 1)
          DrawingText(GapX - \TextPos, GapY, String$, \Front_Color, \Back_Color, hDC, \Fontid)
          DrawingText(GapX - \TextPos + TextWidth(String$), GapY, HilightString$, ContrastColor(\ACColor), \ACColor, hDC, \Fontid)
        EndIf
        
        If \Blink
          Protected BlinkPos.i = GapX - \TextPos + TextWidth(Left(String$, \CursorPosition))
          If \CursorPosition = 0
            BlinkPos + 1
          ElseIf \CursorPosition = Len(\String)
            BlinkPos - 1
          EndIf
          Line(BlinkPos, GapY, 1, TextHeight("A"), \CursorColor)
        EndIf
        
        DrawingMode(#PB_2DDrawing_Default)
        
        Box(\LButtonsWidth + \Border_Size, \Border_Size, \GapX, OutputHeight() - \Border_Size * 2, \Back_Color)
        
        CopyList(\Buttons(), Buttons())
        
        ForEach Buttons()
          If Buttons()\Flag = #SGEx_Left_Button
            DrawImage(ImageID(Buttons()\Image), LeftImgwidth + \Border_Size , \Border_Size)
            LeftImgwidth + ImageWidth(Buttons()\Image)
          Else
            RightImgwidth + ImageWidth(Buttons()\Image)
            DrawImage(ImageID(Buttons()\Image), OutputWidth() - \Border_Size - RightImgwidth, \Border_Size)
          EndIf
        Next
        
        FreeList(Buttons())
        
        If \Flags & #SGEx_ColoredBorder
          If \hasFocus
            color = \Active_Color
          Else
            color = \InActive_Color
          EndIf
          
          DrawingMode(#PB_2DDrawing_Outlined)
          For index = 0 To \Border_Size - 1
            Box(index, index, OutputWidth() - index * 2, OutputHeight() - index * 2, color)
          Next
        EndIf
        
      StopDrawing()
    EndWith
  EndProcedure
  
  
  Procedure CursorThread(*buff.StringGadgetEx_desc)
    With *buff
      Repeat
        If \hasFocus
          PostEvent(#PB_Event_Gadget, GetActiveWindow(), \Gadget, #SGEx_EventType_Blink)
        EndIf
        Delay(\BlinkingTime)
      ForEver
    EndWith
  EndProcedure
  
  
  Procedure GetMousePosition(gadget)
    Protected CurentPosition, X, Y
    Protected *buff.StringGadgetEx_desc
    Protected Length, index, GapX, IsIn.b
    Protected MinDistance.f = Infinity(), CursorPosition.i, Distance.f, CursorX.i
    Protected String$
    
    *buff = GetGadgetData(gadget)
    
    With *buff
      GapX = \Border_Size + \GapX + \LButtonsWidth
      X = GetGadgetAttribute(Gadget, #PB_Canvas_MouseX)
      IsIn = IsInRegion(GapX, 0, GadgetWidth(\Gadget) - \RButtonsWidth - \Border_Size - GapX, GadgetHeight(\Gadget), X, 0)
      If (Not IsIn And \Selected) Or (IsIn And Not \Selected) Or (IsIn And \Selected)
        
        If \Flags & #SGEx_Password
          For index = 1 To Len(\String)
            String$ + #Password_Char$
          Next
        Else
          String$ = \String
        EndIf
        
        Length = Len(String$)
      
        StartDrawing(CanvasOutput(Gadget))
          If \Fontid
            DrawingFont(\Fontid)
          Else
            DrawingFont(#PB_Default)
          EndIf
          For Index = 0 To Length
            CursorX = GapX + TextWidth(Left(String$, Index)) - \TextPos
            Distance = (X-CursorX)*(X-CursorX)
            If Distance < MinDistance
              MinDistance = Distance
              CursorPosition = Index
            EndIf
          Next
        StopDrawing()
        If Not IsInfinity(MinDistance)
          ProcedureReturn CursorPosition
        Else
          ProcedureReturn -1
        EndIf
      Else
       ProcedureReturn -1
      EndIf
    EndWith
  EndProcedure
  
  
  Procedure DeleteSelection(*buff.StringGadgetEx_desc)
     With *buff
        If \CursorLength < 0
           \String = Left(\String, \FixCursorPosition) + Mid(\String, \CursorPosition + 1)
           \CursorPosition = \FixCursorPosition
           \CursorLength = 0
           ProcedureReturn #True
        ElseIf \CursorLength > 0
           \String = Left(\String, \CursorPosition) + Mid(\String, \FixCursorPosition + 1)
           \FixCursorPosition = \CursorPosition
           \CursorLength = 0
           ProcedureReturn #True
        EndIf
     EndWith
  EndProcedure
  
  
  Procedure SelectWord(*buff.StringGadgetEx_desc)
    Protected GapX, GapY, X, Y, index, char.c
    
    With *buff
      GapX = \LButtonsWidth + \Border_Size + \GapX
      GapY = \Border_Size
      If \GapY > -1
        GapY + \GapY
      EndIf
      
      X = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX)
      Y = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY)
      If IsInRegion(GapX, GapY, GadgetWidth(\Gadget) - \RButtonsWidth - \Border_Size - GapX, GadgetHeight(\Gadget) - GapY - \Border_Size, X, Y)
        
        If \Flags & #SGEx_Password
          \FixCursorPosition = 0
          \CursorPosition = Len(\String)
          \CursorLength = \FixCursorPosition - \CursorPosition
        Else
          char = Asc(Mid(\String, \CursorPosition + 1, 1))
          If (char >= ' ' And char <= '/') Or (char >= ':' And char <= '@') Or (char >= '[' And char <= 96) Or (char >= '{' And char <= '~')
            \FixCursorPosition = \CursorPosition
            \CursorPosition + 1
            \CursorLength = \FixCursorPosition - \CursorPosition
          Else
            For index = \CursorPosition To 0 Step -1
              char = Asc(Mid(\String, index, 1))
              If (char >= ' ' And char <= '/') Or (char >= ':' And char <= '@') Or (char >= '[' And char <= 96) Or (char >= '{' And char <= '~')
                Break
              EndIf
            Next
            
            If index = -1
              \FixCursorPosition = 0
            Else
              \FixCursorPosition = index
            EndIf
            
            For index = \CursorPosition + 1 To Len(\String)
              char = Asc(Mid(\String, index, 1))
              If (char >= ' ' And char <= '/') Or (char >= ':' And char <= '@') Or (char >= '[' And char <= 96) Or (char >= '{' And char <= '~')
                Break
              EndIf
            Next
            
            \CursorPosition = index - 1
            
            \CursorLength = \FixCursorPosition - \CursorPosition
            If \CursorLength = 0
              \CursorLength = -1
            EndIf
          EndIf
        EndIf
        
        ProcedureReturn #True
      EndIf
    EndWith
  EndProcedure
  
  
  Procedure CutClipboard(*buff.StringGadgetEx_desc)
    Protected ClipboardText.s
    
    With *buff
      If \CursorLength <> 0
        If \CursorLength < 0
          ClipboardText = Mid(\String, \FixCursorPosition + 1, Abs(\CursorLength))
        Else
          ClipboardText = Mid(\String, \CursorPosition + 1, \CursorLength)
        EndIf
        SetClipboardText(ClipboardText)
        DeleteSelection(*buff)
        UpdateStringGadgetEx(*buff)
      EndIf
    EndWith
  EndProcedure
  
  
  Procedure CopyClipboard(*buff.StringGadgetEx_desc)
    Protected ClipboardText.s
    
    With *buff
      If \CursorLength <> 0
        If \CursorLength < 0
          ClipboardText = Mid(\String, \FixCursorPosition + 1, Abs(\CursorLength))
        Else
          ClipboardText = Mid(\String, \CursorPosition + 1, \CursorLength)
        EndIf
        SetClipboardText(ClipboardText)
      EndIf
    EndWith
  EndProcedure
  
  
  Procedure PasteClipboard(*buff.StringGadgetEx_desc)
    Protected ClipboardText.s, index, char.c
    
    With *buff
      ClipboardText = GetClipboardText()
                
      If \Flags & #SGEx_LowerCase
        ClipboardText = LCase(ClipboardText)
      ElseIf \Flags & #SGEx_UpperCase
        ClipboardText = UCase(ClipboardText)
      ElseIf \Flags & #SGEx_Numeric
        For index = 1 To Len(ClipboardText)
          char = Asc(Mid(ClipboardText, index, 1))
          If char <= '0' Or char >= '9'
            ClipboardText = #Null$
            Break
          EndIf
        Next
      EndIf
                
      If ClipboardText
        DeleteSelection(*buff)
        \String = Left(\String, \CursorPosition) + ClipboardText + Mid(\String, \CursorPosition + 1)
        \CursorPosition + Len(ClipboardText)
        UpdateStringGadgetEx(*buff)
      EndIf
    EndWith
  EndProcedure
  
  
  Procedure SelectACText(*buff.StringGadgetEx_desc, Text$)
    Protected finded.b, ACText$, tmpText$
    
    With *buff
      ForEach \ACTexts()
        ACText$ = Left(\ACTexts()\Text, Len(Text$))
;         tmpText$ = Text$
;         If \ACTexts()\NoCase
;           ACText$ = LCase(ACText$)
;           tmpText$ = LCase(tmpText$)
;         EndIf
;         If ACText$ = tmpText$
;           finded = #True
;           Break
;         EndIf
        
        If \ACTexts()\NoCase
          If LCase(ACText$) = LCase(Text$)
            finded = #True
            Break
          EndIf
        Else
          If ACText$ = Text$
            finded = #True
            Break
          EndIf
        EndIf
      Next
      
      If Not finded
        ResetList(\ACTexts())
      EndIf
    EndWith
  EndProcedure
  
  Procedure FixACText(*buff.StringGadgetEx_desc)
    With *buff
      If ListIndex(\ACTexts()) <> -1
        \String = \ACTexts()\Text
        ResetList(\ACTexts())
      EndIf
    EndWith
  EndProcedure
 
  Procedure StringGadgetExCallback()
    Protected *buff.StringGadgetEx_desc
    Protected CursorPosition
    Protected Update.b
    
    *buff = GetGadgetData(EventGadget())
    
    With *buff
    
      Select EventType()
        Case #SGEx_EventType_Blink
          UpdateStringGadgetEx(*buff)
          
          
        Case #PB_EventType_Focus
          DispatchEvents(*buff, #SGEx_Event_Focus)
          \hasFocus = #True
          Update = #True
          
          
        Case #PB_EventType_LostFocus
          ResetList(\ACTexts())
          \hasFocus = #False
          DispatchEvents(*buff, #SGEx_Event_LostFocus)
          UpdateStringGadgetEx(*buff, #False)
          
          
        Case #PB_EventType_MouseEnter
          ChangeMouseCursor(*buff)
          
          
        Case #PB_EventType_LeftDoubleClick
          If SelectWord(*buff)
            Update = #True
          EndIf
          \TripleTime = ElapsedMilliseconds()
          
          
        Case #PB_EventType_RightClick
          If IsInRegion(\GapX + \Border_Size + \LButtonsWidth, \Border_Size, GadgetWidth(\Gadget) - \GapX - \Border_Size * 2 - \LButtonsWidth - \RButtonsWidth, GadgetHeight(\Gadget) - \Border_Size * 2, GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX), GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY))
            DispatchEvents(*buff, #SGEx_Event_RightClick)
          EndIf
          
          
        Case #PB_EventType_LeftButtonDown
          FixACText(*buff)
          If \TripleTime
            \TripleTime = ElapsedMilliseconds() - \TripleTime
            If \TripleTime < 200
              \FixCursorPosition = 0
              \CursorPosition = Len(\String)
              \CursorLength = -\CursorPosition
              Update = #True
            EndIf
            \TripleTime = #Null
          EndIf
          
          CursorPosition = GetMousePosition(\Gadget)
          If CursorPosition <> -1 And Not Update
            \CursorPosition = CursorPosition
            \FixCursorPosition = CursorPosition
            \CursorLength = 0
            \Selected = #True
            Update = #True
          EndIf
          
          
        Case #PB_EventType_LeftButtonUp
          If Not \Selected
            \Event\Button = CheckButtonClick(*buff)
            If \Event\Button <> -1
              DispatchEvents(*buff, #SGEx_Event_ButtonClick)
            EndIf
          Else
            \Selected = #False
          EndIf
          
          
        Case #PB_EventType_MouseMove
          If \Selected
            CursorPosition = GetMousePosition(\Gadget)
            If CursorPosition <> -1 And \CursorPosition <> CursorPosition
              \CursorPosition = CursorPosition
              \CursorLength = \FixCursorPosition - CursorPosition
              Update = #True
            EndIf
          EndIf
          ChangeMouseCursor(*buff)
          
          
        Case #PB_EventType_Input
          If Not GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #SGEx_Control_Key
            \Event\Input = Chr(GetGadgetAttribute(\Gadget, #PB_Canvas_Input))
            If \Flags & #SGEx_Numeric
              If Asc(\Event\Input) < '0' Or Asc(\Event\Input) > '9'
                \Event\Input = #Null$
              EndIf
            Else
              If \Flags & #SGEx_LowerCase
                \Event\Input = LCase(\Event\Input)
              ElseIf \Flags & #SGEx_UpperCase
                \Event\Input = UCase(\Event\Input)
              EndIf
            EndIf
            
            If \Event\Input
              DeleteSelection(*buff)
              \String = Left(\String, \CursorPosition) + \Event\Input + Mid(\String, \CursorPosition + 1)
              \CursorPosition + 1
              SelectACText(*buff, \String)
              DispatchEvents(*buff, #SGEx_Event_Input)
              Update = #True
            EndIf
          EndIf
            
          
        Case #PB_EventType_KeyDown
          \Event\key = GetGadgetAttribute(\Gadget, #PB_Canvas_Key)
          Select \Event\key
            Case #PB_Shortcut_A
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #SGEx_Control_Key
                FixACText(*buff)
                \FixCursorPosition = 0
                \CursorPosition = Len(\String)
                \CursorLength = -\CursorPosition
                Update = #True
              EndIf
              
              
            Case #PB_Shortcut_X
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #SGEx_Control_Key And Not (\Flags & #SGEx_Password)
                CutClipboard(*buff)
              EndIf
              
              
            Case #PB_Shortcut_C
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #SGEx_Control_Key And Not (\Flags & #SGEx_Password)
                CopyClipboard(*buff)
              EndIf
              
              
            Case #PB_Shortcut_V
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #SGEx_Control_Key
                PasteClipboard(*buff.StringGadgetEx_desc)
                SelectACText(*buff, \String)
              EndIf
              
              
            Case #PB_Shortcut_Back
              If ListIndex(\ACTexts()) = -1
                Update = DeleteSelection(*buff)
                If Not Update
                  If \CursorPosition > 0
                    \String = Left(\String, \CursorPosition - 1) + Mid(\String, \CursorPosition + 1)
                    \CursorPosition - 1
                    Update = #True
                  EndIf
                EndIf
              Else
                ResetList(\ACTexts())
                Update = #True
              EndIf
              
              
            Case #PB_Shortcut_Delete
              If ListIndex(\ACTexts()) = -1
                Update = DeleteSelection(*buff)
                If Not Update
                  If \CursorPosition < Len(\String)
                    \String = Left(\String, \CursorPosition) + Mid(\String, \CursorPosition + 2)
                    Update = #True
                  EndIf
                EndIf
              Else
                ResetList(\ACTexts())
                Update = #True
              EndIf
              
              
            Case #PB_Shortcut_Left
              FixACText(*buff)
              If \CursorPosition > 0
                If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift
                  If \CursorLength = 0
                    \FixCursorPosition = \CursorPosition
                  EndIf
                  \CursorLength + 1
                  \CursorPosition - 1
                Else
                  If \CursorLength < 0
                    \CursorPosition = \FixCursorPosition
                  ElseIf \CursorLength = 0
                    \CursorPosition - 1
                  EndIf
                  \CursorLength = 0
                EndIf
                
                Update = #True
              ElseIf \CursorLength And Not (GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift)
                \CursorLength = 0
                Update = #True
              EndIf
              
              
            Case #PB_Shortcut_Right
              FixACText(*buff)
              If \CursorPosition < Len(\String)
                If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift
                  If \CursorLength = 0
                    \FixCursorPosition = \CursorPosition
                  EndIf
                  \CursorLength - 1
                  \CursorPosition + 1
                Else
                  If \CursorLength > 0
                    \CursorPosition = \FixCursorPosition
                  ElseIf \CursorLength = 0
                    \CursorPosition + 1
                  EndIf
                  \CursorLength = 0
                EndIf
                
                Update = #True
              ElseIf \CursorLength And Not (GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift)
                \CursorLength = 0
                Update = #True
              EndIf
              
              
            Case #PB_Shortcut_Home
              FixACText(*buff)
              \CursorLength = 0
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift
                \FixCursorPosition = \CursorPosition
                \CursorLength = \FixCursorPosition
              EndIf
              \CursorPosition = 0
              Update = #True
              
              
            Case #PB_Shortcut_End
              FixACText(*buff)
              \CursorLength = 0
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift
                \FixCursorPosition = \CursorPosition
                \CursorLength = \FixCursorPosition - Len(\String)
              EndIf
              \CursorPosition = Len(\String)
              Update = #True
              
              
  CompilerIf #Use_Internal_Tab
            Case #PB_Shortcut_Tab
              SetActiveGadget(AGF::GetNextGadget(\Gadget, WindowID(EventWindow())))
              
              
            Case #TabKey_While_Shift_Pressed
              If GetGadgetAttribute(\Gadget, #PB_Canvas_Modifiers) & #PB_Canvas_Shift
                SetActiveGadget(AGF::GetPreviousGadget(\Gadget, WindowID(EventWindow())))
              EndIf
  CompilerEndIf
            
          EndSelect
          
          DispatchEvents(*buff, #SGEx_Event_Key)
          
      EndSelect
      
      If Update
        UpdateStringGadgetEx(*buff, #True)
      EndIf
      
    EndWith
    
  EndProcedure
  
  ;- External Procedures
  Procedure SGEx_Create(Gadget, X, Y, Width, Height, Content$, DefaultString$ = #Null$, Flags.w = #Null)
    Protected Result
    Protected *buff.StringGadgetEx_desc
    
    If Not (Flags & #SGEx_BorderLess) And Not (Flags & #SGEx_ColoredBorder)
      Result = CanvasGadget(Gadget, X, Y, Width, Height, #PB_Canvas_Border | #PB_Canvas_Keyboard)
    Else
      Result = CanvasGadget(Gadget, X, Y, Width, Height, #PB_Canvas_Keyboard)
    EndIf
    
    If Result
      If Gadget = #PB_Any
        Gadget = Result
      EndIf
      
      *buff = AllocateMemory(SizeOf(StringGadgetEx_desc))
      InitializeStructure(*buff, StringGadgetEx_desc)
      SetGadgetData(Gadget, *buff)
      
      With *buff
        \Event\Gadget = Gadget
        \Flags = Flags
        \DefaultString = DefaultString$
        \String = Content$
        
        \Back_Color   = #White
        \Front_Color  = #Black
        CompilerIf #PB_Compiler_OS = #PB_OS_Windows
          \HilightColor = GetSysColor_(#COLOR_HIGHLIGHT)
        CompilerElse
          \HilightColor = $D77800
        CompilerEndIf
        \ACColor = \HilightColor
        \CursorColor  = #Black
        \DefaultTextColor = $999999
        
        \Gadget = Gadget
        \BlinkingTime = 500 ; MiliSeconds
        \GapX = 8
        \GapY = -1
      
        If Flags & #SGEx_ColoredBorder
          \Border_Size = 1
          \Active_Color = #Blue
          \InActive_Color = #Black
        EndIf
        
        BindGadgetEvent(Gadget, @StringGadgetExCallback())
        \hTread = CreateThread(@CursorThread(), *buff)
      EndWith
      
      UpdateStringGadgetEx(*buff)
      
    EndIf
    
    ProcedureReturn Result
  EndProcedure
  
  
  Procedure SGEx_Free(Gadget)
    Protected *buff.StringGadgetEx_desc
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      With *buff
        \hasFocus = #False
        KillThread(\hTread)
      EndWith
      FreeGadget(Gadget)
      ClearStructure(*buff, StringGadgetEx_desc)
      ProcedureReturn #True
    EndIf
  EndProcedure
  
  
  Procedure SGEx_Command(Gadget, Command, Param = #PB_Ignore, lParam = #PB_Ignore)
    Protected *buff.StringGadgetEx_desc
    Protected Update.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      With *buff
        Select Command
          Case #SGEx_Command_ClearSelection
            \CursorLength = #Null
            Update = #True
            
          Case #SGEx_Command_SetSelection
            If lParam < 0
              lParam = Len(\String)
            EndIf
            
            If Param < 0
              Param = 0
            EndIf
            
            If Param <= Len(\String) And lParam <= Len(\String) And Param <> lParam
              \FixCursorPosition = Param
              \CursorPosition = lParam
              \CursorLength = \FixCursorPosition - \CursorPosition
              If \hasFocus
                Update = #True
              EndIf
            EndIf
            
          Case #SGEx_Command_DeleteSelection
            DeleteSelection(*buff)
            Update = #True
            
          Case #SGEx_Command_GetSelectionStart
            If \CursorLength < 0
              ProcedureReturn \FixCursorPosition
            ElseIf \CursorLength > 0
              ProcedureReturn \CursorPosition
            EndIf
            ProcedureReturn -1
            
          Case #SGEx_Command_GetSelectionEnd
            If \CursorLength < 0
              ProcedureReturn \CursorPosition
            ElseIf \CursorLength > 0
              ProcedureReturn \FixCursorPosition
            EndIf
            ProcedureReturn -1
            
          Case #SGEx_Command_SelectionLength
            ProcedureReturn Abs(\CursorLength)
            
          Case #SGEx_Command_Length
            ProcedureReturn Len(\String)
            
          Case #SGEx_Command_Copy
            CopyClipboard(*buff)
            
          Case #SGEx_Command_Cut
            CutClipboard(*buff)
            
          Case #SGEx_Command_Paste
            PasteClipboard(*buff)
            
          Case #SGEx_Command_ActiveColor
            If Param >= 0
              \Active_Color = Param
              Update = #True
            Else
              ProcedureReturn \Active_Color
            EndIf
            
          Case #SGEx_Command_AutoCompleteColor
            If Param >= 0
              \ACColor = Param
              Update = #True
            Else
              ProcedureReturn \ACColor
            EndIf
            
          Case #SGEx_Command_InActiveColor
            If Param >= 0
              \InActive_Color = Param
              Update = #True
            Else
              ProcedureReturn \InActive_Color
            EndIf
            
          Case #SGEx_Command_BackColor
            If Param >= 0
              \Back_Color = Param
              Update = #True
            Else
              ProcedureReturn \Back_Color
            EndIf
            
          Case #SGEx_Command_FrontColor
            If Param >= 0
              \Front_Color = Param
              Update = #True
            Else
              ProcedureReturn \Front_Color
            EndIf
            
          Case #SGEx_Command_DefaultTextColor
            If Param >= 0
              \DefaultTextColor = Param
              Update = #True
            Else
              ProcedureReturn \DefaultTextColor
            EndIf
            
          Case #SGEx_Command_CursorColor
            If Param >= 0
              \CursorColor = Param
              Update = #True
            Else
              ProcedureReturn \CursorColor
            EndIf
            
          Case #SGEx_Command_BorderSize
            If Param >= 0
              If \Flags & #SGEx_ColoredBorder
                \Border_Size = Param
              EndIf
              Update = #True
            Else
              ProcedureReturn \Border_Size
            EndIf
            
          Case #SGEx_Command_Font
            If IsFont(Param)
              \Fontid = FontID(Param)
              Update = #True
            EndIf
            
          Case #SGEx_Command_HilightColor
            If Param >= 0
              \HilightColor = Param
              Update = #True
            Else
              ProcedureReturn \HilightColor
            EndIf
            
          Case #SGEx_Command_GapX
            If Param = #PB_Ignore
              ProcedureReturn \GapX
            Else
              \GapX = Param
              Update = #True
            EndIf
  
          Case #SGEx_Command_GapY
            If Param = #PB_Ignore
              ProcedureReturn \GapY
            Else
              \GapY = Param
              Update = #True
            EndIf
            
          Case #SGEx_Command_UserData
            If Param = #PB_Ignore
              ProcedureReturn \_Data
            Else
              \_Data = Param
            EndIf
            
          Case #SGEx_Command_CursorBlinkingTime
            If Param > 0
              \BlinkingTime = Param
            EndIf
            
        EndSelect
        
        If Update
          UpdateStringGadgetEx(*buff)
        EndIf
      EndWith
    EndIf
    
  EndProcedure

  
  Procedure SGEx_SetText(Gadget, Text$)
    Protected *buff.StringGadgetEx_desc
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      *buff\String = Text$
      *buff\CursorPosition = 0
      *buff\CursorLength = 0
      UpdateStringGadgetEx(*buff)
    EndIf
  EndProcedure
  
  
  Procedure.s SGEx_GetText(Gadget, StartPos = #PB_Ignore, EndPos = #PB_Ignore)
    Protected *buff.StringGadgetEx_desc
    Protected String$
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      With *buff
        If StartPos >= 0 And StartPos < EndPos
          If EndPos < 0
            EndPos = Len(\String)
          EndIf
          String$ = Mid(\String, StartPos + 1, EndPos - StartPos)
        Else
          String$ = \String
        EndIf
      EndWith
      
      ProcedureReturn String$
    EndIf
  EndProcedure
  
  
  Procedure SGEx_InsertText(Gadget, Text$)
    Protected *buff.StringGadgetEx_desc
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas And Text$
      *buff = GetGadgetData(Gadget)
      DeleteSelection(*buff)
      With *buff
        \String = Left(\String, \CursorPosition) + Text$ + Mid(\String, \CursorPosition + 1)
        \CursorPosition + Len(Text$)
      EndWith
      UpdateStringGadgetEx(*buff)
    EndIf
  EndProcedure
  
  
  Procedure SGEx_AddButton(Gadget, ButtonID, Image, Flag.b)
    Protected *buff.StringGadgetEx_desc
    
    If IsImage(Image) And IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas And ButtonID >= 0
      *buff = GetGadgetData(Gadget)
      With *buff
        AddElement(\Buttons())
        \Buttons()\Button = ButtonID
        \Buttons()\Flag = Flag
        \Buttons()\Image = Image
        If Flag = #SGEx_Left_Button
          \LButtonsWidth = CalcButonsWidth(*buff)
        Else
          \RButtonsWidth = CalcButonsWidth(*buff, #False)
        EndIf
        UpdateStringGadgetEx(*buff)
      EndWith
      ProcedureReturn #True
    EndIf
    
  EndProcedure
  
  
  Procedure SGEx_RemoveButton(Gadget, ButtonID)
    Protected *buff.StringGadgetEx_desc
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      With *buff
        ForEach \Buttons()
          If \Buttons()\Button = ButtonID
            If \Buttons()\Flag = #SGEx_Left_Button
              \LButtonsWidth - ImageWidth(\Buttons()\Image)
            Else
              \RButtonsWidth - ImageWidth(\Buttons()\Image)
            EndIf
            DeleteElement(\Buttons())
            Break
          EndIf
        Next
        UpdateStringGadgetEx(*buff)
      EndWith
    EndIf
    
  EndProcedure
  
  
  Procedure SGEx_BindEvent(Gadget, *Callback, EventType = #PB_All)
    Protected *buff.StringGadgetEx_desc
    Protected finded.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas And *Callback
      *buff = GetGadgetData(Gadget)
      With *buff
        If EventType = #PB_All
          EventType = #SGEx_Event_ButtonClick | #SGEx_Event_Input | #SGEx_Event_Key
          EventType | #SGEx_Event_Focus | #SGEx_Event_LostFocus | #SGEx_Event_RightClick
        EndIf
        
        ForEach \Callbacks()
          If \Callbacks()\Callback = *Callback
            \Callbacks()\CEvents | EventType
            finded = #True
            Break
          EndIf
        Next
        
        If Not finded
          AddElement(\Callbacks())
          \Callbacks()\Callback = *Callback
          \Callbacks()\CEvents = EventType
        EndIf
        
      EndWith
    EndIf
  EndProcedure
  
  
  Procedure SGEx_UnbindEvent(Gadget, *Callback, EventType = #PB_All)
    Protected *buff.StringGadgetEx_desc, finded.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas And *Callback
      *buff = GetGadgetData(Gadget)
      With *buff
        If EventType = #PB_All
          EventType = #SGEx_Event_ButtonClick | #SGEx_Event_Input | #SGEx_Event_Key
          EventType | #SGEx_Event_Focus | #SGEx_Event_LostFocus | #SGEx_Event_RightClick
        EndIf
        
        ForEach \Callbacks()
          If \Callbacks()\Callback = *Callback
            \Callbacks()\CEvents ! EventType
            finded = #True
            Break
          EndIf
        Next
        
        If finded And \Callbacks()\CEvents = #Null
          DeleteElement(\Callbacks())
        EndIf
      EndWith
    EndIf
  EndProcedure
  
  
  Procedure SGEx_Resize(Gadget, X = #PB_Ignore, Y = #PB_Ignore, Width = #PB_Ignore, Height = #PB_Ignore)
    Protected *buff.StringGadgetEx_desc
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      ResizeGadget(Gadget, X, Y, Width, Height)
      UpdateStringGadgetEx(*buff)
    EndIf
  EndProcedure
  
  
  Procedure SGEx_AddACText(Gadget, Text$, NoCase.b = #False, Seprator$ = " ")
    Protected *buff.StringGadgetEx_desc
    Protected index, index2, field$
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      With *buff
        If Not (\Flags & #SGEx_Password)
          For index = 1 To CountString(Text$, Seprator$) + 1
            field$ = StringField(Text$, index, Seprator$)
            If \Flags & #SGEx_LowerCase
              field$ = LCase(field$)
            ElseIf \Flags & #SGEx_UpperCase
              field$ = UCase(field$)
            ElseIf \Flags & #SGEx_Numeric
              For index2 = 1 To Len(field$)
                If Asc(Mid(field$, index2, 1)) < '0' Or Asc(Mid(field$, index2, 1)) > '9'
                  field$ = #Null$
                  Break
                EndIf
              Next
            EndIf
            
            If field$
              AddElement(\ACTexts())
              \ACTexts()\Text = field$
              \ACTexts()\NoCase = NoCase
            EndIf
          Next
          SortStructuredList(\ACTexts(), #PB_Sort_Ascending, OffsetOf(ACTexts_desc\Text), TypeOf(ACTexts_desc\Text))
          ResetList(\ACTexts())
        EndIf
      EndWith
    EndIf
    
  EndProcedure
  
  
  Procedure SGEx_RemoveACText(Gadget, Text$, Seprator$ = " ")
    Protected *buff.StringGadgetEx_desc
    Protected index, reset.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *buff = GetGadgetData(Gadget)
      With *buff
        If Text$ = #Null$
          ClearList(\ACTexts())
          reset = #True
        Else
          ForEach \ACTexts()
            For index = 1 To CountString(Text$, Seprator$) + 1
              If \ACTexts()\Text = StringField(Text$, index, Seprator$)
                DeleteElement(\ACTexts())
                reset = #True
                Break
              EndIf
            Next
          Next
        EndIf
        
        If reset
          ResetList(\ACTexts())
        EndIf
      EndWith
    EndIf
    
  EndProcedure
  
  
EndModule
;- END OF MODULE
Last edited by Peyman on Fri Nov 04, 2016 10:16 pm, edited 15 times in total.
Sorry for my bad english.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Custom StringGadget with Image button [CrossPlatform]

Post by IdeasVacuum »

Huge work, thanks for sharing 8)

#StringGadgetEx_FontID seems to be ignored? Perhaps you could add font selections to the example?

Code: Select all

#Font10R = 20
LoadFont(#Font10R,"Arial",10, #PB_Font_HighQuality)
SetStringGadgetExAttribute(7, #StringGadgetEx_FontID, #Font10R)
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

Example :

Code: Select all

;- START OF EXAMPLE
XIncludeFile "StringGadgetEx.pbi"

UsePNGImageDecoder()

CompilerIf Not Defined(White, #PB_Constant)
  #White = $FFFFFF
CompilerEndIf

Enumeration
  #Search_Image
  #SSL_Image
  #Voice_Search_Image
  #Search_BTN
  #SSL_BTN
  #Voice_Search_BTN
  #Font_10
  
  #Menu
  #Menu_Cut
  #Menu_Copy
  #Menu_Paste
  #Menu_Del
EndEnumeration

CatchImage(#Search_Image, ?Search_Btn)
CatchImage(#SSL_Image, ?SSL_Btn)
CatchImage(#Voice_Search_Image, ?Voice_Search_Btn)

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  LoadFont(#Font_10, "Arial", 10, #PB_Font_HighQuality)
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
  LoadFont(#Font_10, "Helvetica", 12)
CompilerElse
  LoadFont(#Font_10, "Arial", 10)
CompilerEndIf

UseModule StringGadgetEx

Global Menu_Gadget


Procedure StringGadgetEx_Callback(*Events.SGEx_EventHelper)
  Protected StartPos
  
  With *Events
    Select \Event
      Case #SGEx_Event_ButtonClick
        Debug "Gadget " + \Gadget + " Clicked on Button " + \Button
        If \Button = #Search_BTN And SGEx_GetText(\Gadget)
          SGEx_RemoveACText(0, "ali abood arezoo")
          MessageRequester("Search", SGEx_GetText(\Gadget))
        EndIf
        
        
      Case #SGEx_Event_Input
        ;Debug *Events\Input
        
        
      Case #SGEx_Event_RightClick
        If IsMenu(#Menu)
          If SGEx_Command(\Gadget, #SGEx_Command_SelectionLength)
            DisableMenuItem(#Menu, #Menu_Cut, #False)
            DisableMenuItem(#Menu, #Menu_Copy, #False)
            DisableMenuItem(#Menu, #Menu_Del, #False)
          Else
            DisableMenuItem(#Menu, #Menu_Cut, #True)
            DisableMenuItem(#Menu, #Menu_Copy, #True)
            DisableMenuItem(#Menu, #Menu_Del, #True)
          EndIf
          
          If GetClipboardText()
            DisableMenuItem(#Menu, #Menu_Paste, #False)
          Else
            DisableMenuItem(#Menu, #Menu_Paste, #True)
          EndIf
          Menu_Gadget = \Gadget
          DisplayPopupMenu(#Menu, WindowID(0))
        EndIf
        
        
      Case #SGEx_Event_Focus
        SGEx_Command(\Gadget, #SGEx_Command_SetSelection, 0, -1)
        Debug "Focus on " + Str(\Gadget)
        
        
      Case #SGEx_Event_Key
        If \key = #PB_Shortcut_Return And \Gadget = 7
          If SGEx_GetText(\Gadget)
            MessageRequester("Search", SGEx_GetText(\Gadget))
          EndIf
        EndIf
    EndSelect
  EndWith
EndProcedure

  
If OpenWindow(0, 0, 0, 644, 300, "StringGadgetEx", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  SGEx_Create(0, 8,  10, 306, 30, "", "Normal StringGadget...", #SGEx_ColoredBorder)
  SGEx_Create(1, 8,  45, 306, 30, "", "Numeric StringGadget", #SGEx_Numeric | #SGEx_ColoredBorder)
  SGEx_Create(2, 8,  80, 306, 30, "", "lowercase...", #SGEx_LowerCase | #SGEx_ColoredBorder)
  SGEx_Create(3, 8, 115, 306, 30, "", "uppercase...", #SGEx_UpperCase | #SGEx_ColoredBorder)
  SGEx_Create(4, 8, 150, 306, 30, "", "Borderless", #SGEx_BorderLess)
  SGEx_Create(5, 8, 185, 306, 30, "", "Bordered")
  SGEx_Create(6, 8, 220, 306, 30, "", "Password", #SGEx_Password | #SGEx_ColoredBorder)
  
  
  SGEx_Create(7, 330, 10, 306, 32, "", "Find a setting", #SGEx_ColoredBorder)
  SGEx_Command(7, #SGEx_Command_BorderSize, 2)
  SGEx_Command(7, #SGEx_Command_ActiveColor, RGB(0, 120, 215))
  SGEx_Command(7, #SGEx_Command_InActiveColor, RGB(23, 23, 23))
  SGEx_AddButton(7, #Search_BTN, #Search_Image, #SGEx_Right_Button)    
  SGEx_BindEvent(7, @StringGadgetEx_Callback())
  
  
  SGEx_Create(8, 330, 47, 306, 32, "https://www.google.com", "Some Site", #SGEx_ColoredBorder)
  SGEx_Command(8, #SGEx_Command_BorderSize, 2)
  SGEx_Command(8, #SGEx_Command_ActiveColor, RGB(0, 120, 215))
  SGEx_Command(8, #SGEx_Command_InActiveColor, RGB(23, 23, 23))
  SGEx_AddButton(8, #SSL_BTN, #SSL_Image, #SGEx_Left_Button)
  
  
  SGEx_Create(9, 330, 84, 306, 32, "", "Search Something", #SGEx_ColoredBorder)
  SGEx_Command(9, #SGEx_Command_BorderSize, 2)
  SGEx_Command(9, #SGEx_Command_ActiveColor, RGB(0, 120, 215))
  SGEx_Command(9, #SGEx_Command_InActiveColor, RGB(23, 23, 23))
  SGEx_AddButton(9, #Search_BTN, #Search_Image, #SGEx_Right_Button)
  SGEx_AddButton(9, #Voice_Search_BTN, #Voice_Search_Image, #SGEx_Right_Button)
  
  
  SGEx_Create(10, 330, 121, 306, 32, "", "Colored and GapX", #SGEx_ColoredBorder)
  SGEx_Command(10, #SGEx_Command_BorderSize, 2)
  SGEx_Command(10, #SGEx_Command_ActiveColor, RGB(0, 120, 215))
  SGEx_Command(10, #SGEx_Command_InActiveColor, RGB(23, 23, 23))
  SGEx_Command(10, #SGEx_Command_GapX, 40)
  SGEx_Command(10, #SGEx_Command_GapY, 5)
  SGEx_Command(10, #SGEx_Command_FrontColor, $FF)
  SGEx_Command(10, #SGEx_Command_HilightColor, $FF00)
  SGEx_Command(10, #SGEx_Command_CursorColor, $FF0000)
  SGEx_Command(10, #SGEx_Command_DefaultTextColor, $8CA926)
  
  SGEx_Create(11, 330, 158, 306, 32, "", "AutoComplete With Case", #SGEx_ColoredBorder)
  SGEx_Command(11, #SGEx_Command_BorderSize, 2)
  SGEx_Command(11, #SGEx_Command_ActiveColor, RGB(0, 120, 215))
  SGEx_Command(11, #SGEx_Command_InActiveColor, RGB(23, 23, 23))
  
  SGEx_Create(12, 330, 195, 306, 32, "", "AutoComplete With NoCase", #SGEx_ColoredBorder)
  SGEx_Command(12, #SGEx_Command_BorderSize, 2)
  SGEx_Command(12, #SGEx_Command_ActiveColor, RGB(0, 120, 215))
  SGEx_Command(12, #SGEx_Command_InActiveColor, RGB(23, 23, 23))
  
  ACText.s = "Else ElseIf EnableDebugger EnableExplicit End EndDataSection " +
             "EndEnumeration EndIf EndImport EndInterface EndMacro EndProcedure " +
             "EndSelect EndStructure EndStructureUnion EndWith Enumeration"
  
  SGEx_AddACText(11, ACText)
  SGEx_Command(11, #SGEx_Command_AutoCompleteColor, $FF00)
  
  SGEx_AddACText(12, ACText, #True)
  
  If CreatePopupMenu(#Menu)      ; creation of the pop-up menu begins...
    MenuItem(#Menu_Cut, "Cut")
    MenuItem(#Menu_Copy, "Copy")
    MenuItem(#Menu_Paste, "Paste")
    MenuItem(#Menu_Del, "Delete")
  EndIf
  
  For index = 0 To 12
    SGEx_Command(index, #SGEx_Command_Font, #Font_10)
    SGEx_BindEvent(index, @StringGadgetEx_Callback())
  Next
  
  ; Remove Right Click event from password gadget
  SGEx_UnBindEvent(6, @StringGadgetEx_Callback(), #SGEx_Event_RightClick)
  
  SetActiveGadget(0)
  SGEx_Command(8, #SGEx_Command_SetSelection, 6, 15)
  
  SetWindowColor(0, #White)
  
  Repeat
    event = WaitWindowEvent()
    
    Select event
      Case #PB_Event_Menu
        Select EventMenu()
          Case #Menu_Cut
            SGEx_Command(Menu_Gadget, #SGEx_Command_Cut)
            
          Case #Menu_Copy
            SGEx_Command(Menu_Gadget, #SGEx_Command_Copy)
            
          Case #Menu_Paste
            SGEx_Command(Menu_Gadget, #SGEx_Command_Paste)
            
          Case #Menu_Del
            SGEx_Command(Menu_Gadget, #SGEx_Command_DeleteSelection)
            
            
        EndSelect
        
    EndSelect
    
    
  Until event = #PB_Event_CloseWindow
  
  For index = 0 To 10
    SGEx_Free(index)
  Next
EndIf

DataSection
  Search_Btn:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C0000001C000000,$DF0D720000000608,$5948700900000094,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$ED2A230B2806090A,$5845740700000099,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $01000027D2EEA800,$ED89485441444906,$D0051430848AB1D5,$C12A482256A2CB3B,$5482FDA7F0B076C6,$02485827E0AD89DA,$ECB74DE6D4558589
    Data.q $78BB032331966CEE,$217783C8A72E3CCB,$04EC4AF6F30BC222,$A594CFEF806FF04F,$2BAEB0000EBAE894,$DA18611CF3C86318,$6BAEA8186198E44B
    Data.q $7389AD69BC7CC632,$E720CE7B5B3CF34E,$DAC69A6D19F60BFC,$086318252943FA73,$529431C7166EE082,$9D679E78D2F3AED6,$C61145182C7FBEF9
    Data.q $5DAFCB2CB671FC71,$F7D0C63002083027,$B0A28A2DB6D61DFD,$4D34D3CFFB442F76,$85294196590AAAA8,$B852941B6DB04924,$BBDE5ED4D348AF5E
    Data.q $D6B492CB2A6B5A9D,$090421218C644444,$2E63BF02EFEA1E21,$811E05DB023C1879,$FFF933CD2D391111,$7F6E77704F04E9E7,$00A12D8D1576CBEC
    Data.q $AE444E4549000000
    Data.b $42,$60,$82
    
  SSL_Btn:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C0000001C000000,$DF0D720000000608,$5948700900000094,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$277E55283711090A,$5845740700000080,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$63894854414449C9,$023A067FFFFFFFFC,$85A8E16A365A7A26,$F1F87F1452160164,$37CD8622E0FDA185,$6AF830303030328E
    Data.q $21649167BA743358,$E2E190B03B6C3E49,$B6197BE3DB0C3BF3,$A1877E7C5C32F7C7,$4FF8642C9254C76C,$FDE0FFFBF76C9002,$35FFE7FBC1FF3873
    Data.q $3E493FE2314923FA,$0480BC832BF3F4FC,$E3F8F0C1202F2F9C,$66D16C48C83C922B,$587BCBCAE18D2331,$CFA78E19942574E5,$32CB887DA242CA24
    Data.q $12EE2FCB86060606,$C216A387C808CC6B,$80E8725912B88E81,$748378302D416CE8,$19A42D470B51C2D4,$98B2719E01910000,$45490000000019E5
    Data.b $4E,$44,$AE,$42,$60,$82
    
    
  Voice_Search_Btn:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1C0000001B000000,$C4D1900000000608,$59487009000000ED,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$234E80352C0E160A,$5845740700000047,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $01000027D2EEA800,$DD894854414449A8,$7FC7185144284B96,$86CA0B0C33B99987,$A63C89A32B0A5158,$8585B59488A15DD1,$0B5B5B2565B29D95
    Data.q $945142C34850AF29,$ABCA21642CA282C7,$453163998EE61DC4,$CBFE3268F32677BA,$79D7CE77EFBEF9FF,$174ACA4D24A52909,$430724C92CC37FE8
    Data.q $4211D53BE3A5B930,$46B0DAF0195956A0,$E5674B726C149AA9,$08828F9600080828,$36A93E34CDAA8301,$52F46277A3754EFA,$789BF3C185D37B02
    Data.q $66D8FD1249998129,$C9874CC4DE8FD6F6,$0775D7B2BBBFB418,$2639003BD0809ADA,$C69A94948F69D767,$C1894D6D0F1D6B7D,$010F9F8400E59DB2
    Data.q $F11D5A90178C6B50,$0965253922CE2E3E,$00272FD001DA8AC2,$2A715AD6742AF018,$C7BF42CB9740AB90,$BB9B0006717F800A,$5BF7E1438C80BBE1
    Data.q $E06455D7CBE46DA9,$EF2533369C6A3A78,$A7A191E1DF792EBC,$6E8752FBC45F2F87,$5280AC09C716D0E6,$25454B0FA7A38CDF,$8D3F3FC738B8F848
    Data.q $8A3237904203B7BE,$40186E372BF5B9BD,$5FA4318997937B60,$868738B939171D33,$20FF44FD3FA8B7B1,$F7D16696DE47A7E1,$8A5810815F5E0977
    Data.q $C97B3A388DDC514B,$1E1F15224E34282A,$310BBD0700376CD7,$B494A58E22FB32E3,$EC2B4C6DBFFAB7F1,$C328AC75DC36A613,$4E454900000000AB
    Data.b $44,$AE,$42,$60,$82
    
EndDataSection
;- END OF EXAMPLE
Last edited by Peyman on Fri Nov 04, 2016 10:20 pm, edited 1 time in total.
Sorry for my bad english.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Custom StringGadget with Image button [CrossPlatform]

Post by davido »

@Peyman,

Another very nice custom gadget.
Thank you for sharing.

I like the elegant way you have made the module cross-platform. :D
DE AA EB
Wolfram
Enthusiast
Enthusiast
Posts: 604
Joined: Thu May 30, 2013 4:39 pm

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Wolfram »

Nice, but on OSX 10.7 it crashes if I close the window.
macOS Catalina 10.15.7
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

@davido,

your welcome, thx for your comment, its really fun to code for all platform i like it :D , this is my second gadget for all platform.

@Wolfram,

i think before the program want to exit all thread of gadgets must be killed so FreeStringGadgetEx added to example please test it again.

as i see on net default font for programs in mac is 'Helvetica' and Arial is exist on ubuntu 16.04 so these font added in example.

new version release :

Code: Select all

;{ Release info...
; 1.00 First release version
;
; 1.10 Changed #StringGadgetEx_FontID to #StringGadgetEx_Font
;      Fixed a problem in event system
;      Fixed some problem in drawing Text with GapY param
;      Fixed problem with hilighing text when gadget dont have focus
;      Fixed a bug in FreeStringGadgetEx that cause crash
;      Added Font in example
;      Added double left click for selecting texts
;}
Sorry for my bad english.
User avatar
falsam
Enthusiast
Enthusiast
Posts: 632
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Custom StringGadget with Image button [CrossPlatform]

Post by falsam »

I appreciate this module. Thank you for sharing.

If you could add copy / paste, it would be absolutely awesome. ^^

➽ Windows 11 64-bit - PB 6.21 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect 🤪
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

@falsam,

yea its a very good idea so i add Cut (CTRL + X), Copy (CTRL + C) and Paste (CTRL + V), and a triple left click for selecting all texts in StringGadgetEx.

new release:

Code: Select all

;{ Release info...
; 1.00 First release version
;
; 1.10 Changed #StringGadgetEx_FontID to #StringGadgetEx_Font
;      Fixed a problem in event system
;      Fixed some problem in drawing Text with GapY param
;      Fixed problem with hilighiting text when gadget dont have focus
;      Fixed a bug in FreeStringGadgetEx that cause crash
;      Added Font in example
;      Added double left click for selecting texts
;
; 1.20 Added CTRL + X, CTRL + C, CTRL + V for cut, copy and paste texts
;      Added Triple Left Click for selecting all text of StringGadgetEx
;}
Sorry for my bad english.
User avatar
falsam
Enthusiast
Enthusiast
Posts: 632
Joined: Wed Sep 21, 2011 9:11 am
Location: France
Contact:

Re: Custom StringGadget with Image button [CrossPlatform]

Post by falsam »

Very good ...... but ^^

Stringgadget numeric, lowercase and uppercase no longer works with the copy / paste.

Thank for this new release.

➽ Windows 11 64-bit - PB 6.21 x64 - AMD Ryzen 7 - NVIDIA GeForce GTX 1650 Ti

Sorry for my bad english and the Dunning–Kruger effect 🤪
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

your are right i didn't think about them :D, now code fixed for numeric, lowercase and uppercase

Code: Select all

;{ Release info...
; 1.00 First release version
;
; 1.10 Changed #StringGadgetEx_FontID to #StringGadgetEx_Font
;      Fixed a problem in event system
;      Fixed some problem in drawing Text with GapY param
;      Fixed problem with hilighiting text when gadget dont have focus
;      Fixed a bug in FreeStringGadgetEx that cause crash
;      Added Font in example
;      Added double left click for selecting texts
;
; 1.20 Added CTRL + X, CTRL + C, CTRL + V for cut, copy and paste texts
;      Added Triple Left Click for selecting all text of StringGadgetEx
;
; 1.21 Fixed problem in CTRL + V for numeric, lowercase and uppercase gadgets
;
;}
Sorry for my bad english.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Custom StringGadget with Image button [CrossPlatform]

Post by davido »

@Peyman,

I noticed that the numeric gadget only allows entry of positive integers.
Is this intentional?
DE AA EB
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

@davido,

yes its intentional, in windows and ubuntu as i test, PB StringGadget don't let you to enter minus character i don't have mac to test it.
In windows you can paste a negative number (a number started with a minus char) but you can't type it, i didn't add this paste future because its not logical.
In ubuntu all characters truncated except numbers no matter you type it or paste it.
Sorry for my bad english.
Wolfram
Enthusiast
Enthusiast
Posts: 604
Joined: Thu May 30, 2013 4:39 pm

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Wolfram »

Hi,

the crash at close window is fixed. Thanks

But copy past does not work. If I change #PB_Canvas_Control to #PB_Canvas_Command past works.
On Command + X and Command + C I write only the letter into the gadget.
With #PB_Canvas_Control nothing is happened, not letter and no copy paste.
macOS Catalina 10.15.7
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Custom StringGadget with Image button [CrossPlatform]

Post by davido »

@Peyman,
Thank you for the explanation. :D
DE AA EB
Peyman
Enthusiast
Enthusiast
Posts: 203
Joined: Mon Dec 24, 2007 4:15 pm
Location: Iran

Re: Custom StringGadget with Image button [CrossPlatform]

Post by Peyman »

@Wolfram,

yes your are right as i see in https://support.apple.com/en-us/HT201236 in mac copy, cut and paste works with Command key instead of control so its added in the code as a compiler directive.
Please test the new code in first post.

@davido

np, thx for your comments.
Sorry for my bad english.
Post Reply