Fltk-rs and fluid: how do I make a button which can show/hide a group?

I'm quite new to Rust and have been making some minimal programs in fltk-rs with fluid to try ideas which should be useful for a game gui. Here I'm trying to make a button which can change the widgets which are displayed in a window by toggling show() and hide() on two groups.

The problem I have is that the groups I want to toggle are not in scope for the button callbacks.

I think that I need to pass a reference to the ui that's instantiated in main() into the button callbacks so that the button callbacks are able to find the groups I want to toggle but I haven't got the slightest idea of how to actually get a reference to the button callbacks through fluid.

my main.rs looks like this:

use fltk::{prelude::*, *};

mod scenes;

fn main() {
    let app = app::App::default();
    let ui_instance = scenes::ui::UserInterface::make_window();
    app.run().unwrap();
}

scenes.rs looks like this:
as this is it obviously doesn't compile because ui_instance isn't in scope. It's just a placeholder since I don't know how to give the button callbacks access to ui_instance.

use fltk::button::Button;
use fltk::{prelude::*, *};

pub mod ui {
    fl2rust_macro::include_ui!("src/mygui.fl");
}

pub fn switch_scene1(btn: &mut Button){
    println!("switch to scene 1");
    ui_instance.group2.deactivate();
    ui_instance.group2.hide();
    ui_instance.group1.activate();
    ui_instance.group1.make_resizable(true);
    ui_instance.group1.show();
}

pub fn switch_scene2(btn: &mut Button){
    println!("switch to scene 2");
    ui_instance.group1.deactivate();
    ui_instance.group1.hide();
    ui_instance.group2.activate();
    ui_instance.group2.make_resizable(true);
    ui_instance.group2.show();
}

this is what the mygui.fl file generated by fluid looks like:

# data file for the Fltk User Interface Designer (fluid)
version 1.0400
header_name {.h}
code_name {.cxx}
decl {use crate::scenes::*;} {private local
}

class UserInterface {open
} {
  Function {make_window()} {open
  } {
    Fl_Window main_window {open
      xywh {482 409 1024 576} type Double labelfont 8 resizable visible
    } {
      Fl_Flex main_flex {open
        xywh {0 0 1024 576} resizable
      } {
        Fl_Group group1 {open
          xywh {0 0 1024 576} resizable
        } {
          Fl_Flex {} {open
            xywh {0 0 1024 576} resizable margins {5 5 5 5} gap 5 set_size_tuples {1  1 100 }
          } {
            Fl_Box {} {
              label {Scene 1}
              xywh {5 5 1014 461} labelfont 13 resizable
            }
            Fl_Button {} {
              label {Switch Scene}
              callback switch_scene2 selected
              xywh {5 471 1014 100} labelfont 13
            }
          }
        }
        Fl_Group group2 {open
          xywh {0 0 1024 576} hide deactivate
        } {
          Fl_Flex {} {open
            xywh {0 0 1024 576} resizable margins {5 5 5 5} gap 5 set_size_tuples {1  1 100 }
          } {
            Fl_Box {} {
              label {Scene 2}
              xywh {5 5 1014 461} labelfont 13
            }
            Fl_Button {} {
              label {Switch Scene}
              callback switch_scene1
              xywh {5 471 1014 100} labelfont 13
            }
          }
        }
      }
    }
  }
}

How can I change this so that the button callbacks are able to find group1 and group2 in their scope?

You have basically 3 options:

Option 1: widget IDs

You can give any widget you want to access a special id. In the Fluid gui, you can set the ID in the widget's properties menu by setting the user data field:
image

Then you can access that widget in your callback using widget_from_id, for example:

let mut group1: Group =  app::widget_from_id("group1").unwrap();

Option 2: Using a closure in the callback field

You can pass a closure in the callback field, instead of passing a function pointer:
So instead of passing switch_scene1 for example. You would pass:

move |button| switch_scene1(group1, group2);

You would have to modify the switch_scene functions to accept group1: &mut Group and group2: &mut Group.
A disadvantage of this approach is it might cause friction with the borrow checker.

Option3: Set the callbacks in your user code.

Instead of setting a callback in the Fluid gui. You would set it in your code. For example:

let ui_instance = scenes::ui::UserInterface::make_window();
let mut group1 = ui_instance.group1.clone();
let mut group2 = ui_instance.group2.clone();
ui_instance.button1.set_callback(move |button| {
    // modify group1 and group2
});
// you can also use function pointers for the callbacks
// and access the groups by id if you give them an id
ui_instance.button1.set_callback(switch_scene1);
1 Like

Thanks for the help. Widget IDs made it easy to get the desired result. :+1:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.