0

I am working on a UI in FLTK, and my basic problem boils down to this:

I have a bunch of widgets on a main Window (input, output, button widgets). Say, 16 items (4rows x 4 coloumns). I need to navigate between the widgets using the arrow keys.

Mainly, if focus is on (r4, c4) (the bottom right corner widget) :

a right arrow press should shift focus to (r1, c1) (top left corner widget).
a left arrow press should shift focus to (r4, c3).
an up arrow press should shift focus to (r3, c4).
a down arrow press should shift focus to (r1, c4).

i.e. navigation should work quite intuitively, according to what we are used to.

By default, while using the arrow (or Tab) keys, the focus changes between the widgets in the order they were created. Up and right always go to next widget (in order of creation) and down and left always go to previous widget (in order of creation).

Is there any way to do this in FLTK? Or do I need to create an algorithm to do this?

harishankarv
  • 328
  • 2
  • 14

2 Answers2

0

Have a look at the program called demo.cxx in the distribution test programs. It appears to do what you want without any special programming.

  1. It starts with focus on the exit button.
  2. When you press tab, focus changes to the button box group
  3. If you then start using the arrow keys, the focus changes the way you'd expect it to.

Here is an example if you need one

#include <FL/FL.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <string>
#include <vector>

int ROWS = 4;
int COLS = 4;
int BUTTON_WID = 40;
int BUTTON_HGT = 40;
int BUTTON_SEP = 5;

// These must exist for the duration otherwise
// we get a load of random text as labels
std::vector<std::string> buttonLab;

Fl_Window* CreateGrid()
{
    int gridwid = (BUTTON_WID + BUTTON_SEP) * COLS + BUTTON_SEP;
    int gridhgt = (BUTTON_HGT + BUTTON_SEP) * ROWS + BUTTON_SEP;
    Fl_Window* grid = new Fl_Window(gridwid, gridhgt, "GridTest");
    grid->begin();

    // Create the labels first - if the vector reallocates
    // the fltk widgets lose the pointers
    char tag[] = "@";
    for (int rr = 0; rr < ROWS; ++rr)
    {
        for (int cc = 0; cc < COLS; ++cc)
        {
            ++tag[0];
            buttonLab.push_back(tag);
        }
    }

    // Create the buttons
    int ix = -1;
    for (int ypos = BUTTON_SEP; ypos < gridhgt; ypos += (BUTTON_HGT + BUTTON_SEP))
    {
        for (int xpos = BUTTON_SEP; xpos < gridwid; xpos += (BUTTON_WID + BUTTON_SEP))
        {
            Fl_Button* button = new Fl_Button(xpos, ypos, BUTTON_WID, BUTTON_HGT, buttonLab[++ix].c_str());
        }
    }
    grid->end();
    return grid;
}

int main(int argc, char* argv[])
{
    Fl_Window* grid = CreateGrid();
    grid->show(argc, argv);
    Fl::run();
    return 0;
}

EDIT: If the widgets are created in a random order, the easiest way to override the navigation is to supply your own Fl_Group::navigation function. This can be done either by

  1. Make Fl_Group::navigation virtual and rebuild FLTK. Then create a new group class based on Fl_Group and override the navigation function.
    • Advantage: it will have all the FLTK updates whenever the package is updated.
    • Disadvantage: someone has to remember to make Fl_Group::navigation virtual whenever a new drop of FLTK is obtained.
  2. Make a copy Fl_Group.c and Fl_Group.h and rename them to a new group class. Rewrite the navigation function.
    • Advantage: no need to mess with FLTK rebuild.
    • Disadvantage: it won't have the Fl_Group updates when FLTK is updated.

Put all your widgets in this new group class and you will be in control of the navigation

cup
  • 7,589
  • 4
  • 19
  • 42
  • Although, in both demo.cxx and your code, we are able to navigate correctly as per requirement, they do so mainly because the order of creation of widgets is such and FLTKs is able assign navigate order correctly. – harishankarv Mar 18 '14 at 13:30
  • In what order are you creating your widgets. – cup Mar 18 '14 at 13:36
  • My problem is this, consider that: -I specifically do not create the widgets in order. I may create (r4, c4) before say (r1, c1) and so on, in a haphazard manner. -Some widgets may be altogether absent. eg. (r3, c3) **may** not be there at all – harishankarv Mar 18 '14 at 13:56
  • Mainly, this requires that I keep adding widgets and removing widgets very frequently, and there are a large number of widgets (created quite haphazardly). So to keep track of their order of creation, etc. is not possible. I gave an example of 4x4 just to keep things simple. – harishankarv Mar 18 '14 at 14:03
  • Are all the widgets of the same type? If they are, you could create them first and then just change the labels. – cup Mar 18 '14 at 14:10
  • 1. I think changing the labels definitely wont help, as it wont change the order in which they were created, and **THAT** is how I suppose FLTK determines order of navigation. 2. And no, widgets are not of the same type, as I have mentioned in the OP. 3. Unless FLTK itself provides a solution, i guess the problem is more about creating the algorithm (or finding it the internet). – harishankarv Mar 18 '14 at 14:29
  • I've updated the answer with an alternative solution. – cup Mar 18 '14 at 17:02
  • Yeah, this is true. This can also be done by creating a handle() method that overrides the Fl_Widget::handle() virtual method, and handling all events, including button presses inside that method. My question however, is **WHAT** is the **ALGORITHM** that should be used for changing the focus! That is, precisely **HOW** the navigation function should be overridden and coded, or **HOW** the handle() method should be coded! – harishankarv Mar 18 '14 at 18:14
  • I believe that since navigation is such a fundamental requirement, there must exist some algorithm already. My idea is something that keeps track of the x, y co-ordinates of all widgets'. Each time an arrow key event is generated, the algorithm determines the next focus by considering: the arrow key pressed and x,y coordinates of current and all other widgets on the screen ( and may involve some sort of calculating distance between the widgets). – harishankarv Mar 18 '14 at 18:25
  • There is already a demo application which shows you how to control focus behaviour. However, you want to move focus with the arrow keys, which is uncommon, and may be confusing to users. Furthermore, if you have some text widgets in your form, you are in trouble if you want to use arrow keys for focus traversal... – DejanLekic Mar 25 '14 at 09:01
0

the routine you want is Fl_Widget->take_focus() .

DragonLord
  • 6,395
  • 4
  • 36
  • 38