How to fix flickering in EditorGadget highlight code

Just starting out? Need help? Post your questions and find answers here.
firace
Addict
Addict
Posts: 902
Joined: Wed Nov 09, 2011 8:58 am

How to fix flickering in EditorGadget highlight code

Post by firace »

The following (Windows only) snippet uses a callback to highlight all asterisks (*) in an EditorGadget.
It works reasonably well, but the line being edited flickers a lot.
Any simple tips on how to fix / improve this? Also any performance optimizations would be welcome! :wink:
If possible, I'd rather keep using the "drawtext_" method rather than alternatives.

Thanks!

PS This is based on code I once found on the German forum, but I can't remember who posted it.

Code: Select all


Prototype PrevProc(hwnd,uMsg,wParam,lParam)
PrevEditProc.PrevProc = 0

Macro RedrawCharacter(word)
  
  If Not CompareMemoryString(*ptr_char,@word,#PB_String_NoCase,Len(word)) 
    SetBkColor_(hdc,$839E9E)                                              
    SendMessage_(hwnd, #EM_POSFROMCHAR, @rect, first_index + ((*ptr_char - @Buffer)/SizeOf(character))) 
    DrawText_(hdc,*ptr_char,Len(word), rect, 0) 
  EndIf
  
EndMacro

Procedure EditCallback(hwnd,uMsg,wParam,lParam)
  Shared PrevEditProc.PrevProc
  
  Protected Buffer.s
  Protected first_index.l
  Protected last_index.l
  Protected rect.RECT
  Protected TextRange.TEXTRANGE
  Protected *ptr_char.Character
  Protected hdc.l , hreg.l
  Protected hFont.l = FontID(1) 
  Protected result
  
  If uMsg = #WM_PAINT
    
    result = PrevEditProc(hwnd,uMsg,wParam,lParam)
    
    SendMessage_(hwnd,#EM_GETRECT,0,@rect)
    
    
    first_index = SendMessage_(hwnd,#EM_CHARFROMPOS,0,rect)
    last_index  = SendMessage_(hwnd,#EM_CHARFROMPOS,0,@rect\right)
    
    If (last_index-first_index) > 0 
      
      Buffer = Space(last_index-first_index) 
      
      TextRange\chrg\cpMin = first_index     
      TextRange\chrg\cpMax = last_index
      TextRange\lpstrText  = @Buffer
      
      SendMessage_(hwnd,#EM_GETTEXTRANGE,0,TextRange) 
      
      hdc = GetDC_(hwnd)
      
      hreg = CreateRectRgn_(rect\left,rect\top,rect\right,rect\bottom) 
      
      SelectObject_(hdc,hreg)      
      
      SelectObject_(hdc,hFont)     
      
      
      *ptr_char = @Buffer
      
      While *ptr_char\c
        
        RedrawCharacter("*")    
        
        *ptr_char + SizeOf(Character)
      Wend
      
      DeleteObject_(hreg) 
      ReleaseDC_(hwnd,hdc)
      
    EndIf
    
    ProcedureReturn result
  EndIf
  
  
  ProcedureReturn PrevEditProc(hwnd,uMsg,wParam,lParam)
EndProcedure



OpenWindow(0,0,0,500,500,"TEST")

LoadFont(1, "Courier New", 14) : SetGadgetFont(-1, FontID(1))

hEdit = EditorGadget(0,0,0,500,500)

PrevEditProc = SetWindowLong_(hEdit,#GWL_WNDPROC,@EditCallback())

For i = 0 To 10
  AddGadgetItem(0,i,"ITEM ***************************")
Next


Repeat
  event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow

RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4659
Joined: Sun Apr 12, 2009 6:27 am

Re: How to fix flickering in EditorGadget highlight code

Post by RASHAD »

Hi ,No way while using Subclassing Editor and #WM_PAINT
Instead try the next
Search any text
Use your preferred colors
Search using right click context menu(select,cop,cut,search)
Or select using StringGadget

Code: Select all

#CFM_BACKCOLOR       =  $4000000
Global Range.CHARRANGE ,PrevText$,_pfrom,_pto

Procedure winCB(hWnd, uMsg, wParam, lParam)
  Protected result = #PB_ProcessPureBasicEvents

  Select uMsg
    Case #WM_CONTEXTMENU
      If wParam = GadgetID(0)
        DisplayPopupMenu(0, WindowID(0))
      EndIf
  EndSelect

  ProcedureReturn result
EndProcedure

Procedure Editor_Color(Gadget, Color ,bColor)
 format.CHARFORMAT2
 format\cbSize = SizeOf(CHARFORMAT2)
 format\dwMask = #CFM_COLOR|#CFM_BACKCOLOR
 format\crTextColor = Color
 format\crBackColor = bColor
 SendMessage_(GadgetID(Gadget), #EM_SETCHARFORMAT, #SCF_SELECTION, @format)
EndProcedure

Procedure FindText(gad,Text$,_from,_to)
_pfrom = _from
_pto = _to
For row = _from To _to
 Count = CountString(GetGadgetItemText(gad,row), Text$) 
 For x = 1 To Count
    Pos = FindString(GetGadgetItemText(gad,row), Text$ ,Pos)
    Range\cpMin = Pos + Pos_2 - 1
    Range\cpMax = (Pos + Pos_2+Len(Text$) - 1)
    Pos + Len(Text$)
    SendMessage_(GadgetID(Gad),#EM_EXSETSEL,0,@Range)
    Editor_Color(Gad,$0000FF,$D0FEFE)              ;Red on Light Yellow
 Next
 Pos = 0
 Pos_2 = Pos_2 + Len(GetGadgetItemText(Gad,row))+1
Next
    Range\cpMin = 0
    Range\cpMax = 0
SendMessage_(GadgetID(Gad),#EM_EXSETSEL,0,@Range)
EndProcedure

Procedure ClearSelect()
For row = _pfrom To _pto
 Count = CountString(GetGadgetItemText(gad,row), PrevText$) 
 For x = 1 To Count
    Pos = FindString(GetGadgetItemText(gad,row), PrevText$ ,Pos)
    Range\cpMin = Pos + Pos_2 - 1
    Range\cpMax = (Pos + Pos_2+Len(PrevText$) - 1)
    Pos + Len(PrevText$)
    SendMessage_(GadgetID(Gad),#EM_EXSETSEL,0,@Range)
    Editor_Color(Gad,$000000,$FFFFFF)                ;Black on White
 Next
 Pos = 0
 Pos_2 = Pos_2 + Len(GetGadgetItemText(Gad,row))+1
Next
    Range\cpMin = 0
    Range\cpMax = 0
SendMessage_(GadgetID(Gad),#EM_EXSETSEL,0,@Range)
EndProcedure

OpenWindow(0, 0, 0, 500, 500, "EditorGadget", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
EditorGadget(0, 10, 10, 480, 450)
LoadFont(1, "Courier New", 14) : SetGadgetFont(0, FontID(1))

If CreatePopupMenu(0)
  MenuItem(1, "Cut")
  MenuItem(2, "Copy")
  MenuItem(3, "Paste")
  MenuItem(4, "Search")
  MenuBar()
  MenuItem( 6, "Quit")
EndIf

Range.CHARRANGE 
For i = 0 To 10 
 Text$ = "ITEM ***************************"
 AddGadgetItem(0, i, Text$)
Next

StringGadget(1,10,470,200,20,"")
ButtonGadget(2,220,470,60,20,"Search")

SetWindowCallback(@winCB())

Repeat
  Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
               Quit = 1
               
        Case #PB_Event_Menu      
          Select EventMenu()  ; To see which menu has been selected
  
            Case 1 ; Cut
              SendMessage_(GadgetID(0),#WM_CUT,0,0)
  
            Case 2 ; Copy
              SendMessage_(GadgetID(0),#WM_COPY,0,0)
  
            Case 3 ; Paste
              SendMessage_(GadgetID(0),#WM_PASTE,0,0)
              
            Case 4
              SendMessage_(GadgetID(0),#WM_COPY,0,0)
              ClearSelect()
              PrevText$ = GetClipboardText()
              FindText(0,GetClipboardText(),0,10)              
  
            Case 6 ; Quit
              Quit = 1
  
          EndSelect
          
        Case #PB_Event_Gadget
               Select EventGadget()
                     Case 2
                           ClearSelect()
                           FindText(0,GetGadgetText(1),0,10)
                           PrevText$ = GetGadgetText(1)
               EndSelect
  EndSelect
Until Quit = 1
Egypt my love
firace
Addict
Addict
Posts: 902
Joined: Wed Nov 09, 2011 8:58 am

Re: How to fix flickering in EditorGadget highlight code

Post by firace »

Thanks RASHAD, but I'm afraid your approach won't work for me as it interferes with undo/redo functionality.
That's why I was looking at the subclassing / WM_PAINT / DrawText solution.

I tried to use some tricks like SendMessage_(GadgetID(0),#WM_SETREDRAW, #False, 0) but they don't seem to help, not sure why.
firace
Addict
Addict
Posts: 902
Joined: Wed Nov 09, 2011 8:58 am

Re: How to fix flickering in EditorGadget highlight code

Post by firace »

Coming back to this one...
I just noticed that the flicker does not happen if very few characters (such as only one or two lines) are shown in the EditorGadget. But as soon as more text is present, the line being edited flickers heavily.
You can reproduce the issue by holding down the * key while in the editorgadget (in my original code).

Any suggestions to fix (or at least improve) it, without rewriting the entire procedure?
Post Reply