Page 1 of 5

EditorGadget with Linenumbers

Posted: Fri Dec 24, 2004 8:56 am
by Stefan Schnell
Hi Community,
can anybody tell me, how to realize an editor gadget with line numbers on the left side, that looks like the PB editor?
Thanks for tips.
Bye
Stefan

Posted: Fri Dec 24, 2004 2:26 pm
by Henrik
Hi
I think i recall a tread about the subject sometime ago, try Search

Best regrads
Henrik

Posted: Fri Dec 24, 2004 5:45 pm
by Stefan Schnell
Hi Henrik,
thanks for your reply, do you mean this thread:
viewtopic.php?t=11191&highlight=?
But that is not what I want. I do not want to know how much lines are in the editor gadget.
Or do you mean another thread? Please send me the url of it, I am searching for it, but I can not find any other with a similiar title.
Thanks
Stefan

Posted: Fri Dec 24, 2004 5:47 pm
by Sparkie
Try this Win only method...

Code: Select all

#PFM_NUMBERINGSTART = $8000
#PFM_NUMBERINGSTYLE = $2000
#PFM_NUMBERINGTAB = $4000
Structure myPARAFORMAT2 
  cbSize.l
  dwMask.l 
  wNumbering.w
  wEffects.w
  dxStartIndent.l
  dxRightIndent.l
  dxOffset.l
  wAlignment.w
  cTabCount.w
  rgxTabs.l[#MAX_TAB_STOPS]
  dySpaceBefore.l
  dySpaceAfter.l
  dyLineSpacing.l
  sStyle.w
  bLineSpacingRule.b
  bOutlineLevel.b
  wShadingWeight.w
  wShadingStyle.w
  wNumberingStart.w
  wNumberingStyle.w
  wNumberingTab.w
  wBorderSpace.w
  wBorderWidth.w
  wBorders.w
EndStructure
egPara.myPARAFORMAT2
egPara\cbSize = SizeOf(myPARAFORMAT2)
egPara\dwMask = #PFM_NUMBERING | #PFM_NUMBERINGSTART | #PFM_NUMBERINGSTYLE | #PFM_NUMBERINGTAB
egPara\wNumbering = 2         ; 2 = 1..2..3 ; 3 = a..b..c ; 4 = A..B..C ; 5 = i...ii...iii ; 6 = I...II...III
egPara\wNumberingStart = 1    ; First number to use
egPara\wNumberingStyle = $300 ; 0 = NUM) ; $100 = (NUM) ; $300 = NUM
egPara\wNumberingTab = 250    ; twips
If OpenWindow(0, 0, 0, 300, 150, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "EditorGadget with Line Numbers") And CreateGadgetList(WindowID(0)) 
  EditorGadget (0, 10, 10, 280, 130) 
  SendMessage_(GadgetID(0), #EM_SETPARAFORMAT, 0, egPara)
  For l = 0 To 5 
    AddGadgetItem(0, l, "Line " + Str(l)) 
  Next 
  Repeat
    event = WaitWindowEvent()
  Until event = #PB_Event_CloseWindow 
EndIf 
End

Posted: Fri Dec 24, 2004 5:57 pm
by fsw
@ sparkie
nice, but if you press the enter key twice (fast), the numbers don't appear anymore...

@stefan
It depends which os you need it for.

The way the pb-editor works is pretty slow, but is one way of doing it.
Sometimes the tab header gets confused and you have to click twice on the tab to see the document you expect.

EDIT:

here some code I found on my hd.
Don't know how wrote it or how good it is...

Code: Select all


#RICHEDIT = #WS_CHILD|#WS_VISIBLE|#WS_VSCROLL|#ES_MULTILINE|#ES_AUTOVSCROLL|#ES_NOHIDESEL
#WINDOW_PARAMETERS = #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_MaximizeGadget

Global RichEditID, hWindow, WindowWidth, WindowHeight
Global hLnFont, rc.RECT, FontHeight, buffer.s, OldRedProc

Procedure Error(message.s, fatal.b)
  MemoryID = AllocateMemory(256)
  FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError_(), 0, MenoryID, 256, 0)
  MessageRequester("Error", message+Chr(10)+Chr(10)+PeekS(MemoryID), 0)
  FreeMemory(0)
  If fatal
    End
  EndIf
EndProcedure

Procedure DrawLineNumbers()
  hDC = GetDC_(RichEditID)
  OldObject = SelectObject_(hDC, hLnFont)
  lineno = SendMessage_(RichEditID, #EM_GETFIRSTVISIBLELINE, 0, 0)+1
  GetClientRect_(RichEditID, rc)
  rc\right = 28
  FillRect_(hDC, rc, GetStockObject_(#GRAY_BRUSH))
  SetBkMode_(hDC, #TRANSPARENT)
  SetTextColor_(hDC, $0FFFF)
  lastline = WindowHeight/FontHeight+lineno
  While lineno<lastline
    buffer = Str(lineno)
    DrawText_(hDC, @buffer, -1, rc, #DT_RIGHT)
    rc\top+FontHeight
    lineno+1
  Wend
  MoveToEx_(hDC, rc\right, 0, #NULL)
  LineTo_(hDC, rc\right, rc\bottom)
  SelectObject_(hDC, OldObject)
  ReleaseDC_(RichEditID, hDC)
EndProcedure

Procedure RedProc(hWnd, uMsg, wParam, lParam)
  Select uMsg
    Case #WM_PAINT
      CallWindowProc_(OldRedProc, hWnd, uMsg, wParam, lParam)
      DrawLineNumbers()
      result = 0
    Default
      result = CallWindowProc_(OldRedProc, hWnd, uMsg, wParam, lParam)
  EndSelect
  ProcedureReturn result
EndProcedure

Procedure WndProc(hWnd, uMsg, wParam, lParam)
  result = #PB_ProcessPurebasicEvents
  Select uMsg
    Case #WM_SIZE
      If hWnd=hWindow And wParam<>#SIZE_MINIMIZED
        WindowWidth = lParam&$ffff
        WindowHeight = lParam>>16
        MoveWindow_(RichEditID, 0, 0, WindowWidth, WindowHeight, 1)
      EndIf
  EndSelect
  ProcedureReturn result
EndProcedure


hWindow = OpenWindow(0, 0, 0, 640, 480, #WINDOW_PARAMETERS, "RichEdit line numbers example")
If hWindow
  SetClassLong_(hWindow, #GCL_HBRBACKGROUND, 0) ; remove resize flicker
  
  If LoadLibrary_("RICHED20.DLL")
    RichClass.s = "RichEdit20A"
  ElseIf LoadLibrary_("RICHED32.DLL")
    RichClass.s = "RichEdit"
  Else
    Error("RichEdit library not present.", 0)
    End
  EndIf
  
  WindowWidth = WindowWidth()
  WindowHeight = WindowHeight()
  
  RichEditID = CreateWindowEx_(#WS_EX_CLIENTEDGE, RichClass, 0, #RICHEDIT, 0, 0, WindowWidth, WindowHeight, hWindow, 0, GetModuleHandle_(0), 0)
  
  If RichEditID
    SendMessage_(RichEditID, #EM_GETRECT, 0, rc)
    rc\left+32
    SendMessage_(RichEditID, #EM_SETRECT, 0, rc)
    lfnt.LOGFONT
    cf.CHARFORMAT
    FontName.s = "Courier New"
    lstrcpy_(@lfnt\lfFaceName[0], @FontName)
    lstrcpy_(@cf\szFaceName[0], @FontName)
    lfnt\lfHeight = -12
    lfnt\lfWeight = 400
    hLnFont = CreateFontIndirect_(lfnt)
    hFont = CreateFontIndirect_(lfnt)
    cf\cbSize = SizeOf(CHARFORMAT)
    cf\dwMask = #CFM_FACE|#CFM_SIZE
    cf\yHeight=(-lfnt\lfHeight)*15
    SendMessage_(RichEditID, #EM_SETCHARFORMAT, #SCF_SELECTION, cf)
    hDC = GetDC_(RichEditID)
    OldObject = SelectObject_(hDC, hFont)
    GetTextExtentPoint32_(hDC, @"WWWW", 4, siz.SIZE)
    FontHeight = siz\cy
    SelectObject_(hDC, OldObject)
    ReleaseDC_(RichEditID, hDC)
    OldRedProc = SetWindowLong_(RichEditID, #GWL_WNDPROC, @RedProc())
    SetWindowCallback(@WndProc())
    
    Repeat
      EventID = WaitWindowEvent()
    Until EventID = #PB_EventCloseWindow

  Else
    Error("Could not create the RichEdit control.", 0)
    End
  EndIf

Else 
  Error("Could not create the main window.", 0)
EndIf

End
Have fun with the richedit gadget...

Posted: Sat Dec 25, 2004 2:43 am
by Henrik
....
*Edit* / i cleared this tread abit up so it more readable, i had had just a littel to much drink yesterday. 8O
Henrik

Posted: Sat Dec 25, 2004 3:03 am
by Henrik
All right found the tread i was thinking off, hope it's what you want..
It was of course. 8) El_Choni who made the code.
Now i hope you can use it..

the link to the tread.
viewtopic.php?t=4887&highlight=editorgadget+linenumber

*Edit*
The Code was not announced by El_Choni as being working, but rather that it had some fault in FontHeight.
My bad that i did'nt read what El_Choni said then, but just tried it and thougt it worked


Look down..
Best regrads
Henrik

Posted: Sat Dec 25, 2004 3:21 am
by Henrik
....
Best Regrads
Henrik

Posted: Sat Dec 25, 2004 3:54 am
by Henrik
....

Best regrads
Henrik

Posted: Sat Dec 25, 2004 6:01 am
by Henrik
*Edit* / i cleared this tread abit up so it more readable, i had had just a littel to much drink yesterday. :roll:

The Code posted here is El_Choni's, i changed a variable or 2, it's a bad hack cuz i don't know what i'm doing, really,
maybe, El_Choni have found a better solution - the PB editor works- sooo ?
/*Edit*


Now, i knew that i couldn't sleep with the stupid hack i gave you, so i had to look at it once more :evil:
First i added #WS_HSCROLL
then text in the editor needs to be 10 Height, if you paste text in the editor.
you still need to check for the users FontMetrics
I don't know now why the changes works ??, but it does on my end

Line 87

Code: Select all

;-------------
    ;Changed
    ;===============================
    lfnt\lfHeight = -13
    ;===============================
    
Line 99

Code: Select all

;-------------
    ;Changed
    ;========================================================
    cf\yHeight=(-lfnt\lfHeight)*15; if user uses BigFonts *13
    ;========================================================
the whole code ps. you need the "Procedure SmallFonts()"

Code: Select all

#RICHEDIT = #WS_CHILD|#WS_VISIBLE|#WS_VSCROLL|#WS_HSCROLL|#ES_MULTILINE|#ES_AUTOVSCROLL|#ES_NOHIDESEL
#WINDOW_PARAMETERS = #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_MaximizeGadget
Global RichEditID, hWindow, WindowWidth, WindowHeight
Global hLnFont, rc.RECT, FontHeight, buffer.s, OldRedProc
Procedure Error(message.s, fatal.b)
Mem=AllocateMemory(256)
  FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError_(), 0, Mem, 256, 0)
;   MessageRequester("Error", message+Chr(10)+Chr(10)+PeekS(MemoryID()), 0)
  FreeMemory(Mem)
  If fatal
    End
  EndIf
EndProcedure
Procedure DrawLineNumbers()
  hDC = GetDC_(RichEditID)
  OldObject = SelectObject_(hDC, hLnFont)
  lineno = SendMessage_(RichEditID, #EM_GETFIRSTVISIBLELINE, 0, 0)+1
  GetClientRect_(RichEditID, rc)
  rc\right = 28
  FillRect_(hDC, rc, GetStockObject_(#GRAY_BRUSH))
  SetBkMode_(hDC, #TRANSPARENT)
  SetTextColor_(hDC, $0FFFF)
  lastline = WindowHeight/FontHeight+lineno
  While lineno<lastline
    buffer = Str(lineno)
    DrawText_(hDC, @buffer, -1, rc, #DT_RIGHT)
    rc\top+FontHeight
    lineno+1
  Wend
  MoveToEx_(hDC, rc\right, 0, #NULL)
  LineTo_(hDC, rc\right, rc\bottom)
  SelectObject_(hDC, OldObject)
  ReleaseDC_(RichEditID, hDC)
EndProcedure
Procedure RedProc(hWnd, uMsg, wParam, lParam)
  Select uMsg
    Case #WM_PAINT
      CallWindowProc_(OldRedProc, hWnd, uMsg, wParam, lParam)
      DrawLineNumbers()
      result = 0
    Default
      result = CallWindowProc_(OldRedProc, hWnd, uMsg, wParam, lParam)
  EndSelect
  ProcedureReturn result
EndProcedure
Procedure WndProc(hWnd, uMsg, wParam, lParam)
  result = #PB_ProcessPurebasicEvents
  Select uMsg
    Case #WM_SIZE
      If hWnd=hWindow And wParam<>#SIZE_MINIMIZED
        WindowWidth = lParam&$ffff
        WindowHeight = lParam>>16
        MoveWindow_(RichEditID, 0, 0, WindowWidth, WindowHeight, 1)
      EndIf
  EndSelect
  ProcedureReturn result
EndProcedure

hWindow = OpenWindow(0, 0, 0, 640, 480, #WINDOW_PARAMETERS, "RichEdit line numbers example")
If hWindow

  SetClassLong_(hWindow, #GCL_HBRBACKGROUND, 0) ; remove resize flicker
  If LoadLibrary_("RICHED20.DLL")
    RichClass.s = "RichEdit20A"
  ElseIf LoadLibrary_("RICHED32.DLL")
    RichClass.s = "RichEdit"
  Else
    Error("RichEdit library not present.", 0)
    End
  EndIf
  WindowWidth = WindowWidth()
  WindowHeight = WindowHeight()
  RichEditID = CreateWindowEx_(#WS_EX_CLIENTEDGE, RichClass, 0, #RICHEDIT, 0, 0, WindowWidth, WindowHeight, hWindow, 0, GetModuleHandle_(0), 0)
  If RichEditID
    SendMessage_(RichEditID, #EM_GETRECT, 0, rc)
    rc\left+32
    SendMessage_(RichEditID, #EM_SETRECT, 0, rc)
    lfnt.LOGFONT
    cf.CHARFORMAT
    FontName.s = "Courier New"
    lstrcpy_(@lfnt\lfFaceName[0], @FontName)
    lstrcpy_(@cf\szFaceName[0], @FontName)
    
    ;-------------
    ;Changed
    ;===============================
    lfnt\lfHeight = -13
    ;===============================
    
    lfnt\lfWeight = 400
    hLnFont = CreateFontIndirect_(lfnt)
    hFont = CreateFontIndirect_(lfnt)
    cf\cbSize = SizeOf(CHARFORMAT)
    cf\dwMask = #CFM_FACE|#CFM_SIZE
    
    ;-------------
    ;Changed
    ;========================================================
    cf\yHeight=(-lfnt\lfHeight)*15; if user uses BigFonts *13
    ;========================================================
    
    SendMessage_(RichEditID, #EM_SETCHARFORMAT, #SCF_SELECTION, cf)
    hDC = GetDC_(RichEditID)
    OldObject = SelectObject_(hDC, hFont)
    GetTextExtentPoint32_(hDC, @"||||", 4, siz.SIZE)
    FontHeight = siz\cy
    SelectObject_(hDC, OldObject)
    ReleaseDC_(RichEditID, hDC)
    OldRedProc = SetWindowLong_(RichEditID, #GWL_WNDPROC, @RedProc())
    SetWindowCallback(@WndProc())
    Repeat
      EventID = WaitWindowEvent()
    Until EventID = #PB_EventCloseWindow
  Else
    Error("Could not create the RichEdit control.", 0)
    End
  EndIf
Else 
  Error("Could not create the main window.", 0)
EndIf
End
*Edit*

The FontMetrics routine, i'm not sure who made it "Think it was Freak" but i have used it in several sources but not the author name, hmm.

Code: Select all

;-Returns 1 if your PC is using small fonts, or 0 if not (eg. large).
Procedure SmallFonts()
    SmallFonts=1 : dt=GetDesktopWindow_() : hdc=GetWindowDC_(dt)
    If hdc
        tm.TEXTMETRIC : PrevMapMode=SetMapMode_(hdc,#MM_TEXT)
        GetTextMetrics_(hdc,tm) : PrevMapMode=SetMapMode_(hdc,PrevMapMode)
        ReleaseDC_(dt,hdc) : If tm\tmHeight>16 : SmallFonts=0 : EndIf
    EndIf
    Debug SmallFonts
    ProcedureReturn SmallFonts
EndProcedure
good night...
Best regrads
Henrik

Posted: Sat Dec 25, 2004 9:11 am
by Stefan Schnell
Hi Henrik, Sparkie and fsw,
thanks a lot, now I have a lot to do to understand and test all your code examples, hope to realize a solution.
Bye
Stefan

Posted: Sat Dec 25, 2004 4:02 pm
by Henrik
@Stefan
To be honest i would go for Sparkie's example, if he could fix the stuff with an empty line ends the linenumber thing,
it needs a callback, maybe a nice RECT for the linenumbers.
Hes example seems more elegant to read to me.
And he knows what hes doing, i don't, the example i pointed you to, seems hard to fix if you wan't the ability to change fonttypes in runtime.

So if i were you i would ask Sparkie if he could maybe add a littel to hes example ...please.. .

Best Regrads
Henrik

Posted: Sun Dec 26, 2004 4:19 am
by Sparkie
Thanks for the vote of confidence Henrik 8O :)

I'll see what I can come up with.

Posted: Sun Dec 26, 2004 3:01 pm
by Henrik
Cool :D

Posted: Sun Dec 26, 2004 7:02 pm
by Sparkie
Here's what I have so far. Tested on WinXPhome with PB 3.92. Still working on optimizing so feel free to contribute. ;)

Code: Select all

UseJPEGImageDecoder()
#SCF_ALL = 4
#PFM_NUMBERINGSTART = $8000
#PFM_NUMBERINGSTYLE = $2000
#PFM_NUMBERINGTAB = $4000
Enumeration
  #LineNumbers
  #Editor
  #Conatiner
  #HideSB
EndEnumeration
Structure myPARAFORMAT2 
  cbSize.l
  dwMask.l 
  wNumbering.w
  wEffects.w
  dxStartIndent.l
  dxRightIndent.l
  dxOffset.l
  wAlignment.w
  cTabCount.w
  rgxTabs.l[#MAX_TAB_STOPS]
  dySpaceBefore.l
  dySpaceAfter.l
  dyLineSpacing.l
  sStyle.w
  bLineSpacingRule.b
  bOutlineLevel.b
  wShadingWeight.w
  wShadingStyle.w
  wNumberingStart.w
  wNumberingStyle.w
  wNumberingTab.w
  wBorderSpace.w
  wBorderWidth.w
  wBorders.w
EndStructure
egPara.myPARAFORMAT2
egPara\cbSize = SizeOf(myPARAFORMAT2)
egPara\dwMask = #PFM_NUMBERING | #PFM_NUMBERINGSTART | #PFM_NUMBERINGSTYLE | #PFM_NUMBERINGTAB
egPara\wNumbering = 2         ; 2 = 1..2..3 ; 3 = a..b..c ; 4 = A..B..C ; 5 = i...ii...iii ; 6 = I...II...III
egPara\wNumberingStart = 1    ; First number to use
egPara\wNumberingStyle = $300 ; 0 = NUM) ; $100 = (NUM) ; $300 = NUM
egPara\wNumberingTab = 350    ; twips
Global oldCallback, egPara
Procedure.l myWindowCallback(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents
  Select msg 
    Case #WM_COMMAND
      Select wparam >>16&$FFFF
        Case #EN_UPDATE
          If wparam &$FFFF = #Editor
            ; --> Need to check if Scrollbar is being removed as needed in Linenumber EditorGadget
            vScroll = GetWindowLong_(GadgetID(#LineNumbers), #GWL_STYLE)
            ; --> If it is, put it back
            If vScroll &~#WS_VSCROLL
              SetWindowLong_(GadgetID(#LineNumbers), #GWL_STYLE, GetWindowLong_(GadgetID(#LineNumbers), #GWL_STYLE) | #WS_VSCROLL)
            EndIf
            ; --> Keep linenumbers in sync with EditorGadget
            currentLine = SendMessage_(GadgetID(#Editor), #EM_LINEFROMCHAR, -1, 0)
            If SetGadgetItemText(#LineNumbers, currentLine, " ", -1) = 0
              If CountGadgetItems(#LineNumbers) < CountGadgetItems(1)
                ; --> Need to have at least 1 character to keep linenumbers going
                AddGadgetItem(#LineNumbers, currentLine, " ")
              ElseIf CountGadgetItems(#LineNumbers) > CountGadgetItems(1)
                RemoveGadgetItem(#LineNumbers, currentLine)
              EndIf
            EndIf
          EndIf
          ; --> Scroll linenumbers along with EditorGadget
          SendMessage_(GadgetID(#Editor), #EM_GETSCROLLPOS, 0, @egOne.POINT)
          egZero.POINT\x = 0
          egZero.POINT\y = egOne\y
          SendMessage_(GadgetID(#LineNumbers), #EM_SETSCROLLPOS, 0, egZero)
          ; --> This hides scrollbar in Linenumbers EditorGadget
          ; --> Maybe a better way????
          InvalidateRect_(GadgetID(#HideSB), 0, 1)
      EndSelect
  EndSelect
  ProcedureReturn result 
EndProcedure 
If OpenWindow(0, 0, 0, 500, 400, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "EditorGadget w/Line Numbers") And CreateGadgetList(WindowID(0)) 
  SetWindowCallback(@myWindowCallback())
  ContainerGadget(#Conatiner, 0, 0, 500, 400)
  EditorGadget(#LineNumbers, 3, 3, 50, 394)
  SendMessage_(GadgetID(#LineNumbers), #EM_SETPARAFORMAT, 0, egPara)
  SendMessage_(GadgetID(#LineNumbers), #EM_SETBKGNDCOLOR, 0, RGB(208, 208, 180))
  ; --> We want to keep a hidden scrollbar in Linenumbers EditorGadget
  SetWindowLong_(GadgetID(#LineNumbers), #GWL_STYLE, GetWindowLong_(GadgetID(#LineNumbers), #GWL_STYLE) | #WS_VSCROLL)
  ; --> readonly for linenumbers
  SendMessage_(GadgetID(#LineNumbers), #EM_SETREADONLY, 1, 0)
  EditorGadget(1, 55, 3, 442, 394)
  SendMessage_(GadgetID(#Editor), #EM_SETBKGNDCOLOR, 0, RGB(228, 228, 200))
  SendMessage_(GadgetID(#Editor), #EM_SETEVENTMASK, 0, #ENM_UPDATE)
  ; --> Container gadget hides scrollbar in Linenumber EditorGadget
  ContainerGadget(#HideSB, 50, 3, 5, 394)
  CloseGadgetList()
  CloseGadgetList()
  ; CHARFORMAT structure used for basic text formatting
  egFormat.CHARFORMAT
  egFormat\cbSize = SizeOf(CHARFORMAT)
  ; we'll set our formatting members to change SIZE
  egFormat\dwMask =  #CFM_SIZE
  ; I'll use 14pt type (yHeight is twips 1/1440 of an inch | 1/20 of printer point)
  egFormat\yHeight = 14*20
  ; send info to both EditorGadgets
  SendMessage_(GadgetID(#LineNumbers), #EM_SETCHARFORMAT, #SCF_ALL, @egFormat)
  SendMessage_(GadgetID(#Editor), #EM_SETCHARFORMAT, #SCF_ALL, @egFormat)
  Repeat
    event = WaitWindowEvent()
    ; --> Keep focus out of linenumbers
    If EventGadgetID() = #LineNumbers
      ActivateGadget(#Editor)
    EndIf
    
  Until event = #PB_Event_CloseWindow  
EndIf 
End