Search code examples
c++inputstring-formattingfltk

How to automatically put newline at text's end in FLTK Multiline_Input?


I am using FLTK 1.3.5 and I would like to use the Multiline_Input object. I wonder if there is a way to automatically put a newline when the inserted text reaches the end of the input field, instead of doing it manually (check the uploaded images for an example). Moreover, the newline should be put at the end of a word. I searched here on SO and on the web, but I was not able to find anything useful.

Input text on one line Input text on multiple lines

Here it is the code used to generate the images above.

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Multiline_Input.H>


int main(int argc, char **argv) {

    Fl_Window *G_win = 0;
    G_win = new Fl_Window(200,200,"Test multi input");

    Fl_Multiline_Input* in;
    in = new Fl_Multiline_Input(50,50,120,100," Test:");

    G_win->end();
    G_win->show(argc, argv);
    
    return Fl::run();
}

Solution

  • Following Basile's suggestion, I investigated more on handling events and then I came up with a solution.

    I derivated a class from the original Fl_Multiline_Input which basically controls that the char[] in Fl_Multiline_input->value() does not overcome the maximum width given by the geometry (considering the current Fl_font). Maybe it is not the best solution but, hey, it works! Of course, more performant/elegant strategies are more than welcome.

    The code is down below.

    #include "mymulti.hpp"
    
    /*
       This is needed for converting a std::string 
       to a char[] (required by Fl_Input). Again, 
       maybe more performant alternative are out there...
    */
    char* str2char(std::string S){
        char *out;
        out =  (char*) malloc ((S.size()+1)*sizeof(char));
        
        strcpy(out,&S[0]);
        out[S.size()] = '\0';
        
        return out;
    }
    
    mymulti::mymulti(int x, int y, int h, int l):Fl_Multiline_Input(x, y, h,l)
    {}
    
    int mymulti::handle(int event)
    {
        switch (event) {
            // When a key is pressed and the widget is waiting for input
            case FL_KEYBOARD:
                return handle_key(event, Fl::event_key());
            default:
                return Fl_Multiline_Input::handle(event);
            };
    }
    
    int mymulti::handle_key(int event, int key) {
    
        
        if (key==FL_BackSpace)
            // Allowing Fl_Multiline_Input to handle the delection of characters
            return Fl_Multiline_Input::handle(event);
        else{
            // Converting to std::string just because manipulation is easer
            std::string s(this->value());
            std::string s2;
            /* 
               Search for the last newline char: 
               the subsequent substring must be shorter 
               than the width of the input field
            */
            std::size_t found = s.find_last_of("\n");
            if (found<std::string::npos)
                s2= s.substr (found);
            else
                s2 = s;
            
            /* 
               Mean length of a char (lower case) 
               under the current fl_font. One can add 
               uppercase letters and/or numbers and/or 
               other symbols.
            */
            double lc = fl_width("abcdefghijklmnopqrstuvwxyz")/26;
            // Maximum length for the substring
            int string_length = this->w()/lc -1;
            // if the substring is longer than the max allowed length, then add a newline
            if (s2.length()>string_length)
                s+="\n";
            // Update the input field    
            this->value(str2char(s));
    
            return Fl_Multiline_Input::handle(event);   
            }
    }