teapot-spreadsheet/src/tpt_choose.cxx

231 lines
5.9 KiB
C++

#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
#include <stdarg.h>
#include <string.h>
class Tpt_Return_Button : public Fl_Return_Button {
public:
int handle(int event) {
if (event == FL_KEYBOARD
&& (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter)) {
simulate_key_action();
do_callback();
return 1;
} else
return Fl_Button::handle(event);
}
Tpt_Return_Button(int x, int y, int w, int h) : Fl_Return_Button(x, y, w, h)
{}
};
static Fl_Window *message_form;
static Fl_Box *message;
static Fl_Box *icon;
static const int N_BUTTONS = 3;
static Fl_Button *button[N_BUTTONS];
static int ret_val;
static const char *iconlabel = "?";
static const char *message_title_default;
Fl_Font fl_message_font_ = FL_HELVETICA;
Fl_Fontsize fl_message_size_ = -1;
static int enableHotspot = 1;
static char avoidRecursion = 0;
// Sets the global return value (ret_val) and closes the window.
static void button_cb(Fl_Widget *, long val) {
ret_val = (int) val;
if (Fl::event_key() == FL_Escape) ret_val = -1;
message_form->hide();
}
// If the window is simply closed, that's the same as hitting escape
static void form_cb(Fl_Widget *, long val) {
ret_val = -1;
message_form->hide();
}
static Fl_Window *makeform() {
if (message_form) {
return message_form;
}
// make sure that the dialog does not become the child of some
// current group
Fl_Group *previously_current_group = Fl_Group::current();
Fl_Group::current(0);
// create a new top level window
Fl_Window *w = message_form = new Fl_Window(410,103);
message_form->callback(form_cb);
(message = new Fl_Box(60, 25, 340, 20))
->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
{Fl_Box* o = icon = new Fl_Box(10, 10, 50, 50);
o->box(FL_THIN_UP_BOX);
o->labelfont(FL_TIMES_BOLD);
o->labelsize(34);
o->color(FL_WHITE);
o->labelcolor(FL_BLUE);
}
w->end(); // don't add the buttons automatically
// create the buttons (right to left)
for (int b=0, x=100*N_BUTTONS+10; b<N_BUTTONS; b++, x -= 100) {
button[b] = new Tpt_Return_Button(x, 70, 90, 23);
button[b]->align(FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
button[b]->callback(button_cb, b);
}
button[0]->shortcut(FL_Escape);
// add the buttons (left to right so arrow keys work)
for (int b = N_BUTTONS-1; b >= 0; --b)
w->add(button[b]);
w->begin();
w->resizable(new Fl_Box(60,10,110-60,27));
w->end();
w->set_modal();
Fl_Group::current(previously_current_group);
return w;
}
/*
* 'resizeform()' - Resize the form and widgets so that they hold everything
* that is asked of them...
*/
static void resizeform() {
int i;
int message_w, message_h;
int text_height;
int button_w[N_BUTTONS], button_h[N_BUTTONS];
int x, w, h, max_w, max_h;
const int icon_size = 50;
message_form->size(410,103);
fl_font(message->labelfont(), message->labelsize());
message_w = message_h = 0;
fl_measure(message->label(), message_w, message_h);
message_w += 10;
message_h += 10;
if (message_w < 340)
message_w = 340;
if (message_h < 30)
message_h = 30;
fl_font(button[0]->labelfont(), button[0]->labelsize());
memset(button_w, 0, sizeof(button_w));
memset(button_h, 0, sizeof(button_h));
for (max_h = 25, i = 0; i < N_BUTTONS; i ++)
if (button[i]->visible())
{
fl_measure(button[i]->label(), button_w[i], button_h[i]);
if (i == 1)
button_w[1] += 20;
button_w[i] += 30;
button_h[i] += 10;
if (button_h[i] > max_h)
max_h = button_h[i];
}
text_height = message_h;
max_w = message_w + 10 + icon_size;
w = -10;
for (int i = 0; i < N_BUTTONS; ++i) w += button_w[i];
if (w > max_w)
max_w = w;
message_w = max_w - 10 - icon_size;
w = max_w + 20;
h = max_h + 30 + text_height;
message_form->size(w, h);
message_form->size_range(w, h, w, h);
message->resize(20 + icon_size, 10, message_w, message_h);
icon->resize(10, 10, icon_size, icon_size);
icon->labelsize(icon_size - 10);
for (x = w, i = 0; i < N_BUTTONS; i ++)
if (button_w[i])
{
x -= button_w[i];
button[i]->resize(x, h - 10 - max_h, button_w[i] - 10, max_h);
}
message_form->init_sizes();
}
int tpt_choose(const char* prompt, const char* op0, const char *op1,
const char* op2, int curx) {
if (avoidRecursion) return 0;
Fl::pushed(0); // stop dragging
avoidRecursion = 1;
makeform();
message_form->size(410,103);
message->label(prompt);
message->labelfont(fl_message_font_);
if (fl_message_size_ == -1) message->labelsize(FL_NORMAL_SIZE);
else message->labelsize(fl_message_size_);
if (op0) {
button[0]->show();
button[0]->label(op0);
button[1]->position(210,70);
}
else { button[0]->hide(); button[1]->position(310,70); }
if (op1) { button[1]->show(); button[1]->label(op1);}
else button[1]->hide();
if (op2) { button[2]->show(); button[2]->label(op2); }
else button[2]->hide();
button[curx]->take_focus();
const char* prev_icon_label = icon->label();
if (!prev_icon_label) icon->label(iconlabel);
resizeform();
if (enableHotspot)
message_form->hotspot(button[0]);
if (op0 && Fl_Widget::label_shortcut(op0))
button[0]->shortcut(0);
else
button[0]->shortcut(FL_Escape);
// set default window title, if defined and a specific title is not set
if (!message_form->label() && message_title_default)
message_form->label(message_title_default);
// deactivate Fl::grab(), because it is incompatible with modal windows
Fl_Window* g = Fl::grab();
if (g) Fl::grab(0);
Fl_Group *current_group = Fl_Group::current(); // make sure the dialog does not interfere with any active group
message_form->show();
Fl_Group::current(current_group);
while (message_form->shown()) Fl::wait();
if (g) // regrab the previous popup menu, if there was one
Fl::grab(g);
icon->label(prev_icon_label);
message_form->label(0); // reset window title
avoidRecursion = 0;
return ret_val;
}