EditorGadget, count words and chars

Just starting out? Need help? Post your questions and find answers here.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

EditorGadget, count words and chars

Post by Fangbeast »

I currently use:

Lines.i = SendMessage_(GadgetID(#MyGadget), #EM_GETLINECOUNT, 0, 0)

To get lines in an EditorGadget. Anyone know of similar functions to get words and characters?

Thanks
Amateur Radio, D-STAR/VK3HAF
infratec
Always Here
Always Here
Posts: 6866
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: EditorGadget, count words and chars

Post by infratec »

Hi Fangbeast,

I think you have to count them on your own.
Counting the characters is easy.
Words is a bit more complicated:
You have to find out white characters and control characters.
The stuff between is a word. (hopefully)

Bernd
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: EditorGadget, count words and chars

Post by davido »

@Fangbeast

Would this link help you. Its by wilbert so its blazin' fast.

http://www.purebasic.fr/english/viewtop ... 14#p449514
DE AA EB
infratec
Always Here
Always Here
Posts: 6866
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: EditorGadget, count words and chars

Post by infratec »

Hi,

I think the wilbert solution does not handle unicode.

Here is my and spacebuddy's solution: (cross platform)

Code: Select all

Structure EditInfoStructure
  Chars.i
  Words.i
  Lines.i
EndStructure


Procedure EditorCount(Gadget.i, *EditInfo.EditInfoStructure)
  
  Protected Text$
  
  
  Text$ = GetGadgetText(Gadget)
  
  *EditInfo\Lines = CountString(Text$, #LF$) + 1
  *EditInfo\Chars = Len(Text$) - ((*EditInfo\Lines - 1) * 2)
  
  While FindString(Text$, #LF$, 0)
    Text$ = ReplaceString(Text$, #LF$, " ")
  Wend
  
  While FindString(Text$, #CR$, 0)
    Text$ = ReplaceString(Text$, #CR$, " ")
  Wend
  
  While FindString(Text$, #TAB$, 0)
    Text$=ReplaceString(Text$, #TAB$, " ")
  Wend
  
  While FindString(Text$, "  ", 0)
    Text$=ReplaceString(Text$, "  ", " ")
  Wend

  If Len(Text$)
    *EditInfo\Words = CountString(Trim(Text$), " ") + 1
  Else
    *EditInfo\Words = CountString(Trim(Text$), " ")
  EndIf
  
EndProcedure
Bernd
infratec
Always Here
Always Here
Posts: 6866
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: EditorGadget, count words and chars

Post by infratec »

Ups,

forgot the TABs.
I updated the listing above.

Bernd
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: EditorGadget, count words and chars

Post by wilbert »

infratec wrote:I think the wilbert solution does not handle unicode.
It does handle unicode and is very fast.
I you don't mind treating all ascii codes below 32 as spaces, the version I posted on the second page of that thread
http://www.purebasic.fr/english/viewtop ... 64#p449564
is even faster, should be cross platform and only requires MMX instead of SSE.
Windows (x64)
Raspberry Pi OS (Arm64)
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: EditorGadget, count words and chars

Post by davido »

@wilbert,

Thanks. I was getting worried as I always have the unicode flag set. Thought I might have other problems as I've moved completely to unicode.

I wrote my own word count but I've had to change to yours; it unbelievably fast. :D :D
DE AA EB
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: EditorGadget, count words and chars

Post by Fangbeast »

I'm putting the code from NotePiddle slowly into the serial number manager but hit a problem. I have to track positioning in the main form ListIconGadget and in the data form editor gadget and both programs used the #WM_Notify message for different things.

How can I merge these two so that I can manage position detection for two different gadgets?

The first callback is using positniong on my data form for RTF effects and the second callback uses positioning for applying strikeout/normal font in the ListIconGadget.

Code: Select all

Procedure WindowCallback(hWnd,uMsg,wParam,lParam)
  Select uMsg
    ; Sparkie/Srod's addition to detect pos in editorgadget and convert to physical line
  Case #WM_NOTIFY
    *nmhdr.NMHDR = lParam
    Select *nmhdr\code
      Case #EN_MSGFILTER
        *msgf.MSGFILTER = lParam
        If *msgf\msg = #WM_RBUTTONDOWN
          ; Debug "Right button pressed"
        EndIf
        
        If *msgf\msg = #WM_LBUTTONDOWN
          clickX = *msgf\lParam &$FFFF
          clickY = *msgf\lParam >>16 &$FFFF
          ;            SetGadgetText(1, "Left button Down at x: " + Str(clickX) + "   y: " + Str(clickY))
          pt.POINT\x  = clickX
          pt\y        = clickY
          pos         =       SendMessage_(*nmhdr\hWndFrom, #EM_CHARFROMPOS,     0, pt)
          line        =       SendMessage_(*nmhdr\hWndFrom, #EM_LINEFROMCHAR,  pos,  0)
          char        = pos - SendMessage_(*nmhdr\hWndFrom, #EM_LINEINDEX,    line,  0)
          ;           Debug "Line index = " + Str(line) + ", character index = " + Str(char)
        ElseIf *msgf\msg = #WM_LBUTTONUP
          clickX = *msgf\lParam &$FFFF
          clickY = *msgf\lParam >>16 &$FFFF
          ;             SetGadgetText(1, "Left button Up at x: " + Str(clickX) + "   y: " + Str(clickY))
          ; Get the selection text's font name.
            cf2.CHARFORMAT2\cbsize = SizeOf(CHARFORMAT2)
            SendMessage_(GadgetID(#Gadget_Data_Details), #EM_GETCHARFORMAT ,#SCF_SELECTION, @cf2)
            If cf2
              ; Highlight the current font used in the font gadget when an item is clicked on
              FaceName.s = PeekS(@cf2\szFaceName)
              ForEach ftd()
                If ftd()\Name = FaceName
                  SetGadgetState(#Gadget_Data_font, ListIndex(ftd()))
                EndIf
              Next
              ; Get the font size. Something is still wrong here, 1 pixel out
              PointSize = Round(cf2\yHeight/20, #PB_Round_Nearest)
              line = CountGadgetItems(#Gadget_Data_size) - 1
              For pos = 0 To line
                If Val(GetGadgetItemText(#Gadget_Data_size, pos)) = PointSize
                  SetGadgetState(#Gadget_Data_size, pos)
                  Break
                EndIf
              Next pos
              ; Get the style of the current font
              cf2\dwMask = #CFM_ITALIC | #CFM_BOLD | #CFM_STRIKEOUT | #CFM_UNDERLINE | #CFM_LINK | #CFM_SUBSCRIPT | #CFM_SUPERSCRIPT
              If cf2\dwEffects &#CFM_BOLD
                FaceStyle.s = "Bold"
                ; "100"
                SetGadgetState(#Gadget_Data_bold, 1)
              Else
                SetGadgetState(#Gadget_Data_bold, 0)
              EndIf
              If cf2\dwEffects &#CFM_ITALIC
                If FaceStyle
                  FaceStyle + " + Italic"
                Else
                  FaceStyle = "Italic"
                EndIf
                SetGadgetState(#Gadget_Data_italic, 1)
              Else
                SetGadgetState(#Gadget_Data_italic, 0)
              EndIf
              If cf2\dwEffects &#CFM_UNDERLINE
                If FaceStyle
                  FaceStyle + " + Underline"
                Else
                  FaceStyle = "Underline"
                EndIf
                SetGadgetState(#Gadget_Data_underline, 1)
              Else
                SetGadgetState(#Gadget_Data_underline, 0)
              EndIf
              If Len(FaceStyle) = 0
                FaceStyle = "Normal"
              EndIf
              ; Tell the user what font, size and style is being used
;             SetStatusBar(1, "Font name: " + FaceName.s + " Size: " + Str(PointSize) + " Style: " + FaceStyle.s)
            EndIf
          EndIf
      EndSelect
      ; FluidByte's part of the callback for his routines
    Case #WM_DRAWITEM   ; #WM_MEASUREITEM
      Protected *lpdis.DRAWITEMSTRUCT = lParam
      If *lpdis\hwndItem = GadgetID(#Gadget_Data_font)                                 
        If *lpdis\itemState & #ODS_SELECTED
          Protected hbrFocus = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
          FillRect_(*lpdis\hDC,*lpdis\rcItem,hbrFocus)
          DeleteObject_(hbrFocus)
          DrawFocusRect_(*lpdis\hDC,*lpdis\rcItem)            
          SetTextColor_(*lpdis\hDC,GetSysColor_(#COLOR_HIGHLIGHTTEXT))
        Else
          Protected hbrFace = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW))
          FillRect_(*lpdis\hDC,*lpdis\rcItem,hbrFace)
          DeleteObject_(hbrFace)
          SetTextColor_(*lpdis\hDC,GetSysColor_(#COLOR_WINDOWTEXT))      
        EndIf   
        Protected *ftd.FONTDATA = GetGadgetItemData(#Gadget_Data_font,*lpdis\itemID)         
        ; * Create Preview Font
        Protected lplf.LOGFONT, hfntPreview
        lplf\lfHeight = -MulDiv_(11,GetDeviceCaps_(*lpdis\hDC,#LOGPIXELSY),72)
        If *ftd\Symbol
          lplf\lfCharSet = #SYMBOL_CHARSET
        EndIf
        PokeS(@lplf\lfFaceName,GetGadgetItemText(#Gadget_Data_font,*lpdis\itemID))
        hfntPreview = CreateFontIndirect_(lplf)
        ; * Draw Font Icons
        If *ftd\Type > -1
          ImageList_Draw_(himlFontType,*ftd\Type,*lpdis\hDC,2,*lpdis\rcItem\top + 3,#ILD_TRANSPARENT)
        EndIf
        ; * Draw Preview Text
        SetBkMode_(*lpdis\hDC,#TRANSPARENT)   
        If *ftd\Symbol
          Protected fsz.SIZE
          *lpdis\rcItem\left + 20
          SelectObject_(*lpdis\hDC,GetStockObject_(#DEFAULT_GUI_FONT))
          GetTextExtentPoint32_(*lpdis\hDC,*ftd\Name,Len(*ftd\Name),fsz)
          DrawText_(*lpdis\hDC,*ftd\Name,-1,*lpdis\rcItem,#DT_SINGLELINE | #DT_VCENTER)   
          *lpdis\rcItem\left + fsz\cx + 3
          SelectObject_(*lpdis\hDC,hfntPreview)
          DrawText_(*lpdis\hDC,"ABC123",6,*lpdis\rcItem, #DT_SINGLELINE | #DT_VCENTER)
        Else
          *lpdis\rcItem\left + 20
          SelectObject_(*lpdis\hDC,hfntPreview)
          DrawText_(*lpdis\hDC,*ftd\Name,-1,*lpdis\rcItem, #DT_SINGLELINE | #DT_VCENTER)
        EndIf   
        DeleteObject_(hfntPreview)
      EndIf
      ProcedureReturn #True
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

; strikeoutfont

Procedure WindowCallback(WindowID.i, Message.i, wParam.i, lParam.i)
  ; 
  ReturnValue.i = #PB_ProcessPureBasicEvents
  ; Turn strikeout off and on as needed
  If Message.i =  #WM_NOTIFY
    *nmhdr.NMHDR = lParam
    *lvCD.NMLVCUSTOMDRAW = lParam
    If *lvCD\nmcd\hdr\hwndFrom = GadgetID(#Gadget_PasswordMuncher_Titles) And *lvCD\nmcd\hdr\code = #NM_CUSTOMDRAW
      Select *lvCD\nmcd\dwDrawStage
        Case #CDDS_PREPAINT
          result = #CDRF_NOTIFYITEMDRAW
        Case #CDDS_ITEMPREPAINT
          result = #CDRF_NOTIFYSUBITEMDRAW;
        Case #CDDS_ITEMPREPAINT | #CDDS_SUBITEM
          thisRow = *lvCD\nmcd\dwItemSpec
          thisCol = *lvCD\iSubItem
          on_off = GetGadgetItemData(#Gadget_PasswordMuncher_Titles, thisRow)
;         If thisCol =  0 And on_off   ; Specifically for column 0. You can change this to any
                                       ; or just use on_off to set all columns
          If on_off
            SelectObject_(*lvCD\nmcd\hdc, FontID(#FontStrikeoutYes))
            result = #CDRF_NEWFONT; | #CDRF_DODEFAULT
          Else
            SelectObject_(*lvCD\nmcd\hdc, FontID(#FontStrikeoutNo))
            result = #CDRF_NEWFONT   
          EndIf
      EndSelect
    EndIf
  EndIf
  ; 
  ProcedureReturn ReturnValue.i
  ; 
EndProcedure
Amateur Radio, D-STAR/VK3HAF
infratec
Always Here
Always Here
Posts: 6866
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: EditorGadget, count words and chars

Post by infratec »

Hi,

I think you have to check the member hwndFrom of the NMHDR

Code: Select all

Case #WM_NOTIFY
  *nmhdr.NMHDR = lParam
  Select *nmhdr\hwndFrom
    case GadgetId(#EditorGadget)
      ...
    case GadgetId(#ListIconGadget)
      ...
  EndSelect
Bernd
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: EditorGadget, count words and chars

Post by Fangbeast »

infratec wrote:Hi,

I think you have to check the member hwndFrom of the NMHDR

Code: Select all

Case #WM_NOTIFY
  *nmhdr.NMHDR = lParam
  Select *nmhdr\hwndFrom
    case GadgetId(#EditorGadget)
      ...
    case GadgetId(#ListIconGadget)
      ...
  EndSelect
Bernd
Thanks Bernd, I'll try that. I hope I never find out how I can do without you when it comes to the API (Scared look!)

Well, you know what I'll be doing tonight!! (Not sleeping).

P.s, the serial manager is looking good. NotePiddle was okay but not very attractive but SerialMuncher is and I am happy. That's 2 applications out of the 80 i've done over the years. (Groan).

And I still have to update the rest (AAARRRGHGH)
Amateur Radio, D-STAR/VK3HAF
infratec
Always Here
Always Here
Posts: 6866
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: EditorGadget, count words and chars

Post by infratec »

RASHAD is our API expert.

I'll try to avoid this, since I very often need to be 'crossplatform'

Bernd
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: EditorGadget, count words and chars

Post by Vera »

Thanks Bernd ~ I much appreciate your cross-platform counter :-)

After I figured out how to make useage of your code I found that single standing characters like e.g. " - " would count as words too and found a way to exclude them.
I added the following prior to your double-space removal:

Code: Select all

For k = 1 To 6
  n$ = StringField("- : _ ' + " + Chr(34), k, " ")
  
  While FindString(Text$, Chr(32) + n$ + Chr(32), 0)
    Text$ = ReplaceString(Text$, Chr(32) + n$ + Chr(32), " ")
  Wend
  
Next
and used this for testing:

Code: Select all

#edi = 0
  If OpenWindow(0, 0, 0, 322, 150, "EditorGadget - count as can", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(#edi, 8, 8, 306, 133)
    For a = 0 To 5
      AddGadgetItem(#edi, a, "Line "+Str(a+1) + " and fürther wÖrds")
    Next
     AddGadgetItem(#edi, -1, "Well - as it's : so nice + add - more ' to check")
 
    EditorCount(#edi, @EditInfo.EditInfoStructure)
    
    Debug Str(EditInfo\Lines) + " - Lines"
    Debug Str(EditInfo\Words) + " - Words"
    Debug Str(EditInfo\Chars) + " - Chars"
    
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  EndIf
No doubt there might be smarter ways to do this ... I just wanted to share my point.

greets to all ~ Vera
Post Reply