I want to create a layout where window is resizable, the main frame is resizable with the window, a fixed status bar at the bottom of the window which only resizes horizontally and always stays stuck to the bottom.
I am new to fltk. I couldn't figure it out from the documentation.
This question is tagged with fltk
and rust
and the OP uses the term "frame" which is the fltk-rs
equivalent to FLTK's "box" or "box type" (see demo code below).
There's an entire chapter about resizing in the FLTK docs: "How Does Resizing Work?" and your particular question is almost described in "Resizing can be simple": basically you add one Fl_Group
(main
) as your main group ("frame") and adjacent to (i.e. below) main
the status bar sb
. Then you make your main
group the resizable()
of the window.
I'm posting a working example in pure FLTK (C++
) with the requested functionality that updates the status bar once every second. I'm leaving the port to Rust (fltk-rs
) to the reader.
//
// Demo: Resizable Window with Status Bar
//
// License: Free to use, Public Domain, ...
//
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <stdio.h> // optional: timer demo
const int ww = 600; // window width
const int wh = 400; // window height
const int sbh = 25; // status bar height
// Optional: timer demo
// Write counter of seconds since start to the status bar
void update_status(void *w) { //
static int sec = 3;
char buf[40];
sprintf(buf, "Time since start: %d seconds", sec++);
Fl_Widget *sb = (Fl_Widget *)w;
sb->copy_label(buf); // update status (label)
sb->redraw(); // draw it
Fl::repeat_timeout(1.0, update_status, w); // repeat in 1 sec
}
int main(int argc, char **argv) {
Fl_Window *win = new Fl_Window(ww, wh, "Resizable with Status Bar");
// create main group (aka "frame")
Fl_Group *main = new Fl_Group(0, 0, ww, wh - sbh);
// add widgets inside the main group
Fl_Box *box = new Fl_Box((ww-300)/2, (wh-sbh-60)/2, 300, 60, "in main group");
box->box(FL_FLAT_BOX);
box->color(FL_YELLOW);
// more widgets here ...
main->end();
// create status bar outside main group
Fl_Box *sb = new Fl_Box(0, wh - sbh, ww, sbh, "This is the status bar");
sb->box(FL_DOWN_BOX);
win->end();
win->resizable(main);
win->size_range(250, 150); // min. window size
win->show(argc, argv);
Fl::add_timeout(3.0, update_status, sb); // optional: timer demo
return Fl::run();
}
The above example uses the "classic" resizing approach. Since FLTK 1.4 (current Git master
) another simple approach would be to use an Fl_Flex
widget with one column and two widgets:
main
group (frame) as the top widgetThe status bar can be made "fixed" which makes the top (main
) group consume the entire space minus the height of the status bar.
Last but not least: the most flexible approach would be to use one or more (nested) Fl_Grid
widget(s) for the layout (also available since FLTK 1.4.0). AFAICT all these widgets are available in fltk-rs
as well.
With a minimal change this can be extended to a fixed menu bar on top, a main group in the middle, and a fixed status bar at the bottom of the window.
Update: Layout with fltk-rs
and Flex
widget:
// ----- Cargo.toml -----
[package]
name = "statusbar"
version = "0.1.0"
edition = "2021"
[dependencies]
fltk = { version = "^1.4", features = ["use-ninja", "use-wayland"] }
// ----- src/main.rs -----
//
// Demo: fltk-rs Resizable Window with Status Bar
//
// License: Free to use, Public Domain, ...
//
use fltk::{
app,
group::{Group, Flex},
prelude::{GroupExt, WidgetBase, WidgetExt, WindowExt},
window::Window,
enums::{Color, FrameType},
frame::Frame,
};
fn main() {
let app = app::App::default().with_scheme(app::Scheme::Oxy);
let mut win = Window::default()
.with_size(500, 450)
.with_label("fltk-rs Layout Demo")
.center_screen();
let mut col = Flex::new(0, 0, 500, 450, "Flex").column();
col.set_color(Color::White);
col.set_frame(FrameType::FlatBox);
// place holder for the top menubar
let mut menubar = Frame::default().with_label("Menu Bar");
menubar.set_frame(FrameType::FlatBox);
menubar.set_color(Color::Yellow);
// main group
let group = Group::new(0, 40, 500, 370, "");
let mut frame1 = Frame::new(60, 100, 200, 100, "Frame 1");
frame1.set_color(Color::Red);
frame1.set_frame(FrameType::FlatBox);
frame1.set_label_color(Color::White);
let mut frame2 = Frame::new(200, 260, 200, 100, "Frame 2");
frame2.set_color(Color::Green);
frame2.set_frame(FrameType::FlatBox);
group.end();
// place holder for the status bar
let mut statusbar = Frame::default().with_label("Status Bar");
statusbar.set_color(Color::Yellow);
statusbar.set_frame(FrameType::FlatBox);
col.end();
// make menubar and statusbar "fixed"
col.fixed(&menubar, 40);
col.fixed(&statusbar, 40);
// make window resizable with the 'col' group
win.resizable(&col);
win.make_resizable(true);
win.end();
win.show();
// run the app ...
app.run().unwrap();
}
Disclaimer: although I'm a FLTK (C++) core developer I'm a beginner with fltk-rs
and thus the fltk-rs
demo will likely be suboptimal. However, it works for me...