Search code examples
godotgdscript

How to use base node/class enums?


Maybe it's a really stupid question, but I can't find the answer on Google.

There is a node in Godot - TextEdit. It has several enums. One of them is called MenuItems. One of these is MENU_CLEAR and "= 3" in grey. The description for it states: "Erases the whole TextEdit text."

My question is: how do I use this info to clear the whole TextEdit text?

I tried simply accessing it with

$TextEdit.MENU_CLEAR -> nothing

I tried going the long way

$TextEdit.MenuItems.MENU_CLEAR -> nothing

I tried putting it as a function call

$TextEdit.MENU_CLEAR() -> nothing

However, if I try to print it, I get it's number

print($TextEdit.MENU_CLEAR) -> "3"

The description of MENU_CLEAR, at least for me, implies there is a function somewhere there, that should be executed once I make a call to MENU_CLEAR. But I do something wrong. Pls, help

Edit1: Here's my piece of code (just checking what works, running everything after IF one line at a time):

if $TextEdit.get_line_count() > 6:
    $TextEdit.text = ""
    $TextEdit.menu_option($TextEdit.MENU_CLEAR)

Here's what I want to do:

if $TextEdit.get_line_count() > 6:
    $TextEdit.select(1, 0, 1, 0)    #selects the oldest line
    $TextEdit.menu_option($TextEdit.MENU_CUT)    #deletes it

Here's the screenshot of what I get now See the slider on the right side And here's what I want it to be Just 6 lines So there should always be only 6 lines at once on the screen, and the old lines should be deleted. That's where I encountered problems with enums, and that was the reason for the post. P.S. Read only is set to false


Solution


  • Clearing TextEdit

    I would use $TextEdit.text = "" to clear all the text.


    To address your question. The MENU_CLEAR is a constant. It has the value 3. By itself it does nothing a 3 would not do.

    However, enum (which are lists of constants with a name) are defined because something uses them. To find out what, I suggest you search for the name of the enum (which is MenuItems in this case) in the documentation (in particular on the same class).

    In this case we find the menu_option method. From the documentation:

    void menu_option ( int option )

    Triggers a right-click menu action by the specified index. See MenuItems for a list of available indexes.

    Thus, you would use it like this:

    $TextEdit.menu_option(TextEdit.MENU_CLEAR)
    

    Yes, this also works:

    $TextEdit.menu_option($TextEdit.MENU_CLEAR)
    

    Or you can do it like this (which is the same thing, except it less clear what it means):

    $TextEdit.menu_option(3)
    

    Removing lines from the start of TextEdit

    Let us say we want to remove lines at the start. The number of lines we will remove will be lines_to_remove (e.g. 1).

    We can do this using menu_option. Like this:

    1. Select the lines we want to remove. In other words, select form the start of the first line (0), to the start of the first line that will stay (lines_to_remove):

      $TextEdit.select(0, 0, lines_to_remove, 0)
      
    2. Clear cut:

      $TextEdit.menu_option(TextEdit.MENU_CUT)
      

      This will remove the selected text. However, it will also set the clipboard.

    Alternatively, we can manipulate text. For example:

    var lines:Array = $TextEdit.text.split("\n")
    var new_text := ""
    for index in lines.size() - lines_to_remove:
        if index > 0:
            new_text += "\n"
    
        new_text += str(lines[index + lines_to_remove])
    
    $TextEdit.text = new_text
    

    Here I get the text $TextEdit.text and split it by the new line, which gives me an Array. Then I concatenate the elements form the Array that I want to keep (i.e. skipping the ones I want to remove), And set the result back to $TextEdit.text.


    Regardless of the approach you will find that the cursor will be placed at the start of the text.

    So, we are going to store the position before manipulating the text:

    var cursor_line:int = $TextEdit.cursor_get_line()
    var cursor_column:int = $TextEdit.cursor_get_column()
    

    And then set it back... Well, actually we want to subtract the number of lines we removed and then set it back:

    cursor_line -= lines_to_remove
    $TextEdit.cursor_set_line(cursor_line)
    $TextEdit.cursor_set_column(cursor_column)
    

    If this resulted in a negative cursor_line, it will be placed on the first line. I suppose I could check and set both cursor_line and cursor_column to zero in that case, but it has not been a problem while trying this out.


    Limiting the number of lines of TextEdit

    Now, if you want to make sure you have at most a give number of lines (e.g. six lines). We can read how many lines we have, subtract the maximum you allow, and if the result is positive, that is how many lines have to remove:

    var target_number_of_lines := 6
    var lines_to_remove:int = $TextEdit.get_line_count() - target_number_of_lines
    if lines_to_remove > 0:
        pass # rest of the code here
    

    Why would you need to do this instead of just removing the first line? Because the user might paste multiple lines at once. Speaking of which, this is intended to run on the "text_changed" signal (although it would also work on _process):

    func _on_TextEdit_text_changed() -> void:
        var target_number_of_lines := 6
        var lines_to_remove:int = $TextEdit.get_line_count() - target_number_of_lines
        if lines_to_remove > 0:
            var cursor_line:int = $TextEdit.cursor_get_line()
            var cursor_column:int = $TextEdit.cursor_get_column()
    
            $TextEdit.select(0, 0, lines_to_remove, 0)
            $TextEdit.menu_option(TextEdit.MENU_CUT)
    
            cursor_line -= lines_to_remove
            $TextEdit.cursor_set_line(cursor_line)
            $TextEdit.cursor_set_column(cursor_column)
    

    Since this version is cutting the text, it writes the clipboard.


    Manipulating the text property also works (and does not write the clipboard). This is the code:

    func _on_TextEdit_text_changed() -> void:
        var target_number_of_lines := 6
        var lines_to_remove:int = $TextEdit.get_line_count() - target_number_of_lines
        if lines_to_remove > 0:
            var cursor_line:int = $TextEdit.cursor_get_line()
            var cursor_column:int = $TextEdit.cursor_get_column()
    
            var lines:Array = $TextEdit.text.split("\n")
            var new_text := ""
            for index in lines.size() - lines_to_remove:
                if index > 0:
                    new_text += "\n"
    
                new_text += str(lines[index + lines_to_remove])
    
            $TextEdit.text = new_text
    
            cursor_line -= lines_to_remove
            $TextEdit.cursor_set_line(cursor_line)
            $TextEdit.cursor_set_column(cursor_column)