Workaround for GetGadgetItemText() with wrapped text in Linux and MacOS

Share your advanced PureBasic knowledge/code with the community.
User avatar
Shardik
Addict
Addict
Posts: 1988
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Workaround for GetGadgetItemText() with wrapped text in Linux and MacOS

Post by Shardik »

In the EditorGadget without the flag #PB_Editor_WordWrap you are able to get a single specified line of text from the EditorGadget using GetGadgetItemText(). This works cross-platform:

Code: Select all

EnableExplicit

DataSection
  Data.S "The quick brown"
  Data.S "fox jumps over"
  Data.S "the lazy dog."
  Data.S #EOT$
EndDataSection

Define EditorContents.S
Define FontSize.I
Define i.I
Define TextLine.S

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    FontSize = 21
  CompilerCase #PB_OS_MacOS
    FontSize = 27
  CompilerDefault
    FontSize = 21
CompilerEndSelect

OpenWindow(0, 200, 100, 240, 125, "EditorGadget without WordWrap")
EditorGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)
SetGadgetFont(0, LoadFont(0, "Arial", FontSize))

Repeat
  Read.S TextLine

  If TextLine <> #EOT$
    AddGadgetItem(0, -1, TextLine)
  EndIf 
Until TextLine = #EOT$

; ----- Wait until text is displayed in Linux

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  Delay(50)
  While WindowEvent() : Wend
CompilerEndIf

; ----- Get non-wrapped text lines

For i = 0 To CountGadgetItems(0) - 1
  EditorContents + "Line " + Str(i) + ": " + #DQUOTE$ +
    GetGadgetItemText(0, i) + #DQUOTE$ + #CR$
Next i

MessageRequester("Contents of EditorGadget",
  EditorContents,
  #PB_MessageRequester_Info)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow


Unfortunately in an EditorGadget with the flag #PB_Editor_WordWrap the function GetGadgetItemText() only works in Windows. In Linux and MacOS GetGadgetItemText() returns the complete wrapped text block in the first line 0!

You may therefore try the following workaround with the procedure GetTextFromLine() which also allows to retrieve single lines from a wrapped text block in Linux (using GTK2 or GTK3) and MacOS (in Windows it calls GetGadgetItemText(), so working cross-platform):

Code: Select all

EnableExplicit

#Text = "The quick brown fox jumps over the lazy dog."

Define FontSize.I
Define i.I
Define Info.S

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  ImportC ""
    gtk_text_view_get_iter_at_position(*TextView.GtkTextView,
      *Iter.GtkTextIter, Trailing.I, x.I, y.I)
  EndImport
CompilerEndIf

Procedure.S GetTextFromLine(EditorID.I, LineNumber.I)
  Protected TextLine.S

  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      Protected EndIter.GtkTextIter
      Protected LineCount.I
      Protected LineHeight.I
      Protected StartIter.GtkTextIter
      Protected TextBlockHeight.I
      Protected *TextBuffer
      Protected TextView.I = GadgetID(EditorID)
      Protected y.I = LineNumber * LineHeight

      ; ----- Get height of a single wrapped text line for font used in
      ;       EditorGadget
      
      If StartDrawing(WindowOutput(0))
        DrawingFont(GetGadgetFont(EditorID))
        LineHeight = TextHeight("Test")
        StopDrawing()
      EndIf

      ; ----- Get wrapped text line

      *TextBuffer = gtk_text_view_get_buffer_(TextView)
      gtk_text_buffer_get_start_iter_(*TextBuffer, @StartIter)
      gtk_text_view_get_line_yrange_(TextView, @StartIter, 0, @TextBlockHeight)
      y = LineNumber * LineHeight
      gtk_text_view_get_iter_at_position(TextView, @StartIter, 0, 0, y)
      LineCount = TextBlockHeight / LineHeight
      
      If LineNumber >= LineCount - 1
        gtk_text_buffer_get_end_iter_(*TextBuffer, @EndIter)
      Else
        y + LineHeight
        gtk_text_view_get_iter_at_position(TextView, @EndIter, 0, 0, y)
      EndIf
      
      TextLine = PeekS(gtk_text_buffer_get_text_(*TextBuffer, @StartIter,
        @EndIter, 0), -1, #PB_UTF8)
    CompilerCase #PB_OS_MacOS
      Protected Index.I
      Protected GlyphCount.I
      Protected LayoutManager.I
      Protected LineCount.I
      Protected LineRange.NSRange
      Protected *LineRange
      Protected Location.I
      
      LayoutManager = CocoaMessage(0, GadgetID(EditorID), "layoutManager")
      GlyphCount = CocoaMessage(0, LayoutManager, "numberOfGlyphs")
      *LineRange = @LineRange
      
      While Index < GlyphCount
        CocoaMessage(0, LayoutManager,
          "lineFragmentRectForGlyphAtIndex:", Index,
          "effectiveRange:@", @*LineRange)
        Index = LineRange\length + LineRange\location
        
        If LineCount = LineNumber
          Location = LineRange\location

          If LineCount > 0
            Location + 1
          EndIf
          
          TextLine =  Mid(#Text, Location, LineRange\length)
          Break
        EndIf
        
        LineCount + 1
      Wend
    CompilerCase #PB_OS_Windows
      TextLine = GetGadgetItemText(EditorID, LineNumber)
  CompilerEndSelect

  ProcedureReturn TextLine
EndProcedure

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    FontSize = 21
  CompilerCase #PB_OS_MacOS
    FontSize = 27
  CompilerDefault
    FontSize = 21
CompilerEndSelect

OpenWindow(0, 200, 100, 240, 125, "EditorGadget with WordWrap")
EditorGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20,
  #PB_Editor_WordWrap)
SetGadgetFont(0, LoadFont(0, "Arial", FontSize))
SetGadgetText(0, #Text)

; ----- Wait until text is displayed in Linux

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  Delay(50)
  While WindowEvent() : Wend
CompilerEndIf

; ----- Get wrapped text lines

For i = 0 To 2
  Info + "Line " + Str(i + 1) + ": " + #DQUOTE$ + GetTextFromLine(0, i) +
    #DQUOTE$ + #CR$
Next i

MessageRequester("Contents of EditorGadget", Info, #PB_MessageRequester_Info)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
User avatar
idle
Always Here
Always Here
Posts: 5039
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Workaround for GetGadgetItemText() with wrapped text in Linux and MacOS

Post by idle »

thanks that will be very useful
Post Reply