2

FLTK is a callback based GUI system but there are times that I need a user to input an acceptable answer into a Fl_Input widget before a function can return.

This seems to require updating the widget, collecting the answer then returning the answer if it is valid.

So, in essence let's say I have a function called int get_int(Fl_Input i). This function needs to continually update the Fl_Input, validate the contents by attempting to cast the value() to an int, clear Fl_Input if the validation fails, and finally return the cast int from the function. This validation should happen on the press of enter key. (I plan to also have functions to return cast strings and floats but they'll work the same way)

This is actually part of a scripting system and FLTK is the GUI. The embedded language is waiting to get a proper int from my Fl_Input but FLTK can't update and process events because it has not completed the main loop. I can't easily do this via normal FLTK callbacks it seems because they must return void and I'll have many types of casting and validation on my single input depending on the context of the object reading from it.

Thanks to anyone who can help me!

EDIT here is some rough example code of what I need.

Embeddable Common Lisp needs to wrap the get_int function but I'm not sure how to update all widgets with an interrupt and also break the loop with a callback which can't affect the loop directly. (boolean flag maybe?)

#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <Fl/Fl_Input.H>
#include <Fl/Fl_Button.H>
#include <stdexcept>

int get_int(Fl_Input* i)
{
  int temp = 0;
  while(True)
  {

    // not sure how to update here
    // at this point, button and field need to update
    // also somehow validate needs to be done on Enter button press
    // but callbacks can't interact with this part of the code directly
    // to validate and end the loop here

    try
    {
      temp = std::stoi(i->value());
    }
    catch(...)
    {
      std::cout << "Invalid conversion to int" << i->value() << std::endl;
      i->value("");
    }
  }
  return temp;
}

void field_callback(Fl_Widget * w, void *d)
{
  // This callback simulates Embeddable Common Lisp calling wrapped get_int
  // Once a number is valid, it is converted and passed to back to Lisp
  int something = get_int((Fl_Input*)w);
  std::cout << something << std::endl;
}

int main()
{
  Fl_Window *w = new Fl_Window(200, 32);
  Fl_Input *i = new Fl_Input(0, 0, 128, 24, "");
  Fl_Button *b = new Fl_Button(128, 0, 32, 24, "Simulate Request");
  b->callback(field_callback);
  w->show();

  return(Fl::run());
}
  • Could you post some example (commented) code of what you're trying to do? – bku_drytt Apr 20 '16 at 04:45
  • 1
    You nailed the problem: The FLTK main loop isn't running. Think about how to fix that. – Ulrich Eckhardt Apr 20 '16 at 06:09
  • Have you tried experimenting with the WHEN directives? Have a look at NumericInput – cup Apr 20 '16 at 06:21
  • I've attached some code that should explain a bit better. Since I don't expect you to have Embeddable Common Lisp I've made the button click simulate what it would need when trying to get the field value from within a wrapped get_int or get_float or get_text function. All deal with the same Fl_Input instance. – RyanBurnside Apr 20 '16 at 07:19
  • When do you want the validation done? If it is when the user has typed CR, add b->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED) before the callback – cup Apr 21 '16 at 12:10

1 Answers1

0

Well after some help on FLTK's mailing list I've composed an example for those looking to do a similar thing. This was just off the cuff and might be buggy for production use. Be sure to debug and not copy/paste directly.

#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <string>
#include <iostream>


Fl_Window* win = new Fl_Window(240, 128, "Loop n Prompt");
Fl_Button* button = new Fl_Button(5, 5, 128, 24, "Simulate Prompt");
Fl_Input* input = new Fl_Input(5, 96, 230, 24, "");
Fl_Box* prompt_msg = new Fl_Box(5, 48, 230, 24, "");

std::string get_input(const char* prompt,  Fl_Input *input)
{
  // Lock all widgets not pertaining to field here
  button->deactivate();
  prompt_msg->label(prompt);

  // Open up the input for value entry
  input->readonly(false);
  input->activate();

  while(! input->readonly())
  {
    Fl::wait();
  }

  // other groups activate here
  button->activate();

  // Have a funny feeling about c -> std::string conversion double check...
  std::string return_string = input->value();

  // Reset input and prompt to ""
  input->value("");
  prompt_msg->label("");

  return return_string;
}

void input_CB(Fl_Widget *w, void* data)
{
  Fl_Input* ptr = (Fl_Input*)w;
  ptr->readonly(true);
}

void button_CB(Fl_Widget *w, void* data)
{
  // Simulate something needing these values RIGHT NOW
  std::cout << "Got " << get_input("Please enter name", input) << std::endl;
  std::cout << "Got " << get_input("Please enter mother's name", input) << std::endl;
  std::cout << "Got " << get_input("Please enter father's name", input) << std::endl;

  // Now try a standard loop until thing
  std::string password = "";
  while(password != "password")
  {
    password = get_input("You must enter 'password'", input);
  }

  std::cout << "Nice job you answered correctly to exit the loop!" << std::endl;
}

int main()
{
  // Callback setup
  input->callback((Fl_Callback*)input_CB);
  button->callback((Fl_Callback*)button_CB);

  // Entry field does callback when enter key pressed
  input->when(FL_WHEN_ENTER_KEY_ALWAYS);

  // Show the window and all children
  win->show();
  return(Fl::run());
}