Basic Univers

; Thanks to Sparkie
Structure LN
  Editor_Ed.l
  Container.l
  Editor_Ln.l
EndStructure

Global NewList LNumber.LN()
Global LN
Procedure LN_Init(gadget)
  Find =#False
  ForEach LNumber()
    If LNumber()\editor_ed = gadget
      Find =#True
      Break
    EndIf
  Next
  If Find =#False
    LastElement(LNumber())
    AddElement(LNumber())
    LNumber()\Editor_ed = gadget
    gadget_x = GadgetX(gadget)
    gadget_y = GadgetY(gadget)
    gadget_width = GadgetWidth(gadget)
    gadget_height = GadgetHeight(gadget)
 
    ResizeGadget(gadget, gadget_x + 50, #PB_Ignore, gadget_width - 50, #PB_Ignore)
    LNumber()\Container = ContainerGadget(#PB_Any, gadget_x, gadget_y, 50, gadget_height, #PB_Container_BorderLess)
    LNumber()\Editor_Ln = EditorGadget(#PB_Any, 0, 0, 50, gadget_height)
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SHOWSCROLLBAR, #SB_VERT, #False)
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SHOWSCROLLBAR, #SB_HORZ, #False)
    CloseGadgetList()
    ;{
    AddGadgetItem(LNumber()\Editor_Ln, - 1, "1 ")
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SETBKGNDCOLOR, 0, RGB(248, 248, 220))
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SETREADONLY, 1, 0)
   
    SendMessage_(GadgetID(gadget), #EM_SETEVENTMASK, 0, #ENM_UPDATE | #ENM_CHANGE | #ENM_SCROLL | #ENM_KEYEVENTS)
    egFormat.CHARFORMAT
    egFormat\cbSize = SizeOf(CHARFORMAT)
    egFormat\dwMask =  #CFM_SIZE | #CFM_COLOR
    ; size = Editor_GetFontSize(gadget)
    size = 8
    egFormat\yHeight = size*20
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SETCHARFORMAT, #SCF_ALL, @egFormat)
    SendMessage_(GadgetID(LNumber()\editor_ed), #EM_GETSCROLLPOS, 0, @egOne.POINT)
      egOne\x = 0
      SendMessage_(GadgetID(LNumber()\editor_ed), #EM_HIDESELECTION, #True, 0)
        SetGadgetText(LNumber()\editor_ed, GetGadgetText(LNumber()\editor_ed))
      SendMessage_(GadgetID(LNumber()\editor_ed), #EM_HIDESELECTION, #False, 0)
    SendMessage_(GadgetID(LNumber()\editor_ed), #EM_SETSCROLLPOS, 0, egOne)
   
    ;}
   
    ;{ Mise à droite des colonnes
    egPara.PARAFORMAT2
    egPara\cbSize = SizeOf(PARAFORMAT2)
    egPara\dwMask = #PFM_ALIGNMENT
    egpara\wAlignment = #PFA_RIGHT
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SETPARAFORMAT, #SCF_ALL, @egPara)
    ; récupère le texte de la sélection
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_GETSEL, @StartSel, @EndSel)
    Buffer$ = Space(EndSel - StartSel)
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_GETSELTEXT, 0, @Buffer$)
    ; récupère la position des barres de scroll
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_GETSCROLLPOS, 0, @scrollP.POINT)
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_REPLACESEL, #True, @Buffer$)
    ; définit la position des barres de scroll
    SendMessage_(GadgetID(LNumber()\Editor_Ln), #EM_SETSCROLLPOS, 0, scrollP.POINT)
    ;}
    SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETMARGINS, 1|2, 0|(10<<16))
  EndIf
  ProcedureReturn
EndProcedure
Procedure LN_Stop(gadget)
  If IsGadget(gadget)
    Find =- 1
    ForEach LNumber()
      If LNumber()\editor_ed = gadget
        Find = ListIndex(LNumber())
        Break
      EndIf
    Next
    If Find>- 1
      SelectElement(LNumber(), Find)
      editor_ed = LNumber()\editor_ed
      container = LNumber()\container
      editor_ln = LNumber()\editor_ln
      DeleteElement(LNumber(), 1)
     
      size_container = GadgetWidth(container)
      ; libération des gadgets
      FreeGadget(editor_ln)
      FreeGadget(container)
      ; redimensionnement de l'éditeur
      ResizeGadget(editor_ed, GadgetX(editor_ed)- size_container, #PB_Ignore, GadgetWidth(editor_ed)+ size_container, #PB_Ignore)
    EndIf
  EndIf
EndProcedure
Procedure LN_Update(param =- 1)
  If param =- 1
    ForEach LNumber()
      LN_Update(LNumber()\editor_ed)
    Next
  Else
    ForEach LNumber()
      If LNumber()\editor_ed = param
        Break
      EndIf
    Next
    If EventGadget() = LNumber()\editor_ln
      firstline = SendMessage_(GadgetID(LNumber()\editor_ln), #EM_GETFIRSTVISIBLELINE, 0, 0)
     ; Editor_Select(LNumber()\editor_ln,firstline+2,1,firstline+2,1)
      SetActiveGadget(LNumber()\editor_ed)
    EndIf
  EndIf
EndProcedure
Procedure LN_SetColorText(Gadget, Color)
  ForEach LNumber()
    If LNumber()\editor_ed = Gadget
      Break
    EndIf
  Next
  If ListIndex(LNumber()) > - 1
    SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETBKGNDCOLOR, 0, Color)
    SendMessage_(GadgetID(LNumber()\editor_ed), #EM_GETSCROLLPOS, 0, @egOne.POINT)
    egOne\x = 0
    SendMessage_(GadgetID(LNumber()\editor_ed), #EM_SETSCROLLPOS, 0, egOne)
  EndIf
EndProcedure
Procedure LN_SetColorBack(Gadget, Color)
  ForEach LNumber()
    If LNumber()\editor_ed = Gadget
      Break
    EndIf
  Next
  If ListIndex(LNumber()) > - 1
    egFormat.CHARFORMAT
    egFormat\cbSize = SizeOf(CHARFORMAT)
    SendMessage_(GadgetID(LNumber()\editor_ln), #EM_GETCHARFORMAT, #SCF_ALL, @egFormat)
    egFormat\dwMask |  #CFM_SIZE | #CFM_COLOR
    size = 8 ; Editor_GetFontSize(LNumber()\editor_ed)
    egFormat\yHeight = size*20
    egFormat\crTextColor = Color
    SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETCHARFORMAT, #SCF_ALL, @egFormat)
    SendMessage_(GadgetID(LNumber()\editor_ed), #EM_GETSCROLLPOS, 0, @egOne.POINT)
    egOne\x = 0
    SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETSCROLLPOS, 0, egOne)
  EndIf
EndProcedure
Procedure LN_Resize(Gadget, Valeur)
  ForEach LNumber()
    If LNumber()\editor_ed = Gadget
      Break
    EndIf
  Next
  If ListIndex(LNumber()) > - 1
    ResizeGadget(LNumber()\Container, #PB_Ignore, #PB_Ignore, GadgetWidth(LNumber()\Container)+ Valeur, #PB_Ignore)
    ResizeGadget(LNumber()\editor_ln, #PB_Ignore, #PB_Ignore, GadgetWidth(LNumber()\editor_ln)+ Valeur, #PB_Ignore)
    ResizeGadget(LNumber()\editor_ed, GadgetX(LNumber()\editor_ed)+ Valeur, #PB_Ignore, GadgetWidth(LNumber()\editor_ed)- Valeur, #PB_Ignore)
  EndIf
EndProcedure

Procedure Test_SetColor(Gadget)
  ForEach LNumber()
    If LNumber()\editor_ed = Gadget
      Break
    EndIf
  Next
  SendMessage_(GadgetID(LNumber()\editor_ed), #EM_SETBKGNDCOLOR, 0, RGB(Random(255), Random(255), Random(255)))
EndProcedure


Procedure.l LN_Callback(hwnd, msg, wparam, lparam)
  Shared previousItems
  result = #PB_ProcessPureBasicEvents
  Find =#False
  ForEach LNumber()
    If IsGadget(LNumber()\editor_ed)
      If GadgetID(LNumber()\editor_ed)= lparam
        Find =#True
        Break
      EndIf
    EndIf
  Next
  If Find =#True
    Select msg
      Case #WM_COMMAND
        If IsGadget(LNumber()\editor_ed) And IsGadget(LNumber()\editor_ln)
          If lparam = GadgetID(LNumber()\editor_ed)
            Select wparam >>16&$FFFF
              Case #EN_VSCROLL
                ; --> Keep linenumbers in sync with EditorGadget scrolling up or down (clicking scroll buttons)
                SendMessage_(GadgetID(LNumber()\editor_ed), #EM_GETSCROLLPOS, 0, @egOne.POINT)
                ; --> Keep numbers from scrolling left
                egOne\x = 0
                SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETSCROLLPOS, 0, egOne)
              Case #EN_UPDATE
                SendMessage_(GadgetID(LNumber()\editor_ed), #EM_SETCHARFORMAT, #SCF_ALL, @egFormat)
                ; --> Keep linenumbers in sync with EditorGadget scrolling up or down (dragging scroll thumb)
                SendMessage_(GadgetID(LNumber()\editor_ed), #EM_GETSCROLLPOS, 0, @egOne.POINT)
                ; --> Keep numbers from scrolling left
                egOne\x = 0
                SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETSCROLLPOS, 0, egOne)
              Case #EN_CHANGE
                ; --> Keep linenumbers in sync with EditorGadget adding or removing items
                currentLine = SendMessage_(GadgetID(LNumber()\editor_ed), #EM_LINEFROMCHAR, - 1, 0)+ 1
                lnItems = CountGadgetItems(LNumber()\editor_ln)
                egItems = CountGadgetItems(LNumber()\editor_ed)
                ; --> For now I just clear the entire number list when items are
                ; --> added or removed. >>>>>>>>>>>>>  Causes slight flicker so find a better way! <<<<<<<<<<<<<<
                If egItems > lnItems
                  For i = lnItems + 1 To egItems
                    AddGadgetItem(LNumber()\editor_ln, i, Str(i))
                  Next i
                EndIf
                If egItems < lnItems
                  For i = lnItems To egItems Step - 1
                    RemoveGadgetItem(LNumber()\editor_ln, i)
                  Next i
                  ; --> Remove the last CR/LF left behind by RemoveGadgetItem
                  ; --> Readonly off for linenumbers
                  SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETREADONLY, 0, 0)
                  SendMessage_(GadgetID(LNumber()\editor_ln), #WM_KEYDOWN, #VK_BACK, 0)
                  SendMessage_(GadgetID(LNumber()\editor_ln), #WM_KEYUP, #VK_BACK, 0)
                  SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETREADONLY, 1, 0)
                EndIf
                ; --> Keep linenumbers in sync with EditorGadget scrolling up or down (dragging scroll thumb)
                SendMessage_(GadgetID(LNumber()\editor_ed), #EM_GETSCROLLPOS, 0, @egOne.POINT)
                ; --> Keep numbers from scrolling left
                egOne\x = 0
                SendMessage_(GadgetID(LNumber()\editor_ln), #EM_SETSCROLLPOS, 0, egOne)
                previousItems = egItems
            EndSelect
          EndIf
        EndIf
    EndSelect
  EndIf
  ProcedureReturn result
EndProcedure

If OpenWindow(0, 0, 0, 700, 500, "EditorGadget w/Line Numbers", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
  SetWindowCallback(@LN_Callback())
  ;{
  CreateMenu(1, WindowID(0))
  MenuTitle("F&ile")
    MenuItem(104, "&Quit" + Chr(9) + "Ctrl+Q")
  MenuTitle("&AZERTY")
    MenuItem(121, "Colonne > &Fond")
    MenuItem(122, "Colonne > &Texte")
    MenuItem(123, "&Editor > Fond")
    MenuItem(124, "Colonne > Taille +")
    MenuItem(125, "Colonne > Taille -")
    MenuItem(126, "Stop")
    MenuItem(127, "Commencer")
    AddKeyboardShortcut(0, #PB_Shortcut_F1, 121)
    AddKeyboardShortcut(0, #PB_Shortcut_F2, 122)
    AddKeyboardShortcut(0, #PB_Shortcut_F3, 123)
    AddKeyboardShortcut(0, #PB_Shortcut_F4, 124)
    AddKeyboardShortcut(0, #PB_Shortcut_F5, 125)
    AddKeyboardShortcut(0, #PB_Shortcut_F6, 126)
    AddKeyboardShortcut(0, #PB_Shortcut_F7, 127)
  ;}
  EditorGadget(4, 40, 0, 250, 400)
  LN_Init(4)
  list = EditorGadget(#PB_Any, 290, 0, 250, 400)
  LN_Init(list)
  For i = 0 To 100
    AddGadgetItem(4, i, "Line" + Str(i))
    AddGadgetItem(list, i, "Line" + Str(i))
  Next
  Repeat
    event = WaitWindowEvent()
    LN_Update()
    Select event
      Case #PB_Event_Menu
        Select EventMenu()
          Case 104
            CloseWindow(0)
          Case 121
            LN_SetColorText(4, RGB(Random(255), Random(255), Random(255)))
            LN_SetColorText(list, RGB(Random(255), Random(255), Random(255)))
          Case 122
            LN_SetColorBack(4, RGB(Random(255), Random(255), Random(255)))
            LN_SetColorBack(list, RGB(Random(255), Random(255), Random(255)))
          Case 123
            Test_SetColor(4)
            Test_SetColor(list)
          Case 124
            LN_Resize(4, 5)
            LN_Resize(list, 5)
          Case 125
            LN_Resize(4, - 5)
            LN_Resize(list, - 5)
          Case 126
            LN_Stop(4)
            LN_Stop(list)
          Case 127
            LN_Init(4)
            LN_Init(list)
        EndSelect
    EndSelect
  Until event = #PB_Event_CloseWindow
EndIf
End