1998-10-19 20:46:58 +00:00
|
|
|
//
|
2003-05-21 01:50:14 +00:00
|
|
|
// "$Id: Fl_Menu.cxx,v 1.18.2.12.2.26 2003/05/21 01:50:13 easysw Exp $"
|
1998-10-19 20:46:58 +00:00
|
|
|
//
|
|
|
|
// Menu code for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2003-01-30 21:46:07 +00:00
|
|
|
// Copyright 1998-2003 by Bill Spitzak and others.
|
1998-10-19 20:46:58 +00:00
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Library General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Library General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Library General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
// USA.
|
|
|
|
//
|
2000-06-05 21:21:24 +00:00
|
|
|
// Please report all bugs and problems to "fltk-bugs@fltk.org".
|
1998-10-19 20:46:58 +00:00
|
|
|
//
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
// Warning: this menu code is quite a mess!
|
|
|
|
|
|
|
|
// This file contains code for implementing Fl_Menu_Item, and for
|
|
|
|
// methods for bringing up popup menu hierarchies without using the
|
|
|
|
// Fl_Menu_ widget.
|
|
|
|
|
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/Fl_Menu_Window.H>
|
|
|
|
#include <FL/Fl_Menu_.H>
|
|
|
|
#include <FL/fl_draw.H>
|
2001-12-20 14:41:44 +00:00
|
|
|
#include <stdio.h>
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
int Fl_Menu_Item::size() const {
|
|
|
|
const Fl_Menu_Item* m = this;
|
|
|
|
int nest = 0;
|
|
|
|
for (;;) {
|
|
|
|
if (!m->text) {
|
|
|
|
if (!nest) return (m-this+1);
|
|
|
|
nest--;
|
|
|
|
} else if (m->flags & FL_SUBMENU) {
|
|
|
|
nest++;
|
|
|
|
}
|
|
|
|
m++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const Fl_Menu_Item* Fl_Menu_Item::next(int n) const {
|
|
|
|
if (n < 0) return 0; // this is so selected==-1 returns NULL
|
|
|
|
const Fl_Menu_Item* m = this;
|
|
|
|
int nest = 0;
|
|
|
|
while (n>0) {
|
|
|
|
if (!m->text) {
|
|
|
|
if (!nest) return m;
|
|
|
|
nest--;
|
|
|
|
} else if (m->flags&FL_SUBMENU) {
|
|
|
|
nest++;
|
|
|
|
}
|
|
|
|
m++;
|
|
|
|
if (!nest && m->visible()) n--;
|
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
// appearance of current menus are pulled from this parent widget:
|
|
|
|
static const Fl_Menu_* button;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// tiny window for title of menu:
|
|
|
|
class menutitle : public Fl_Menu_Window {
|
|
|
|
void draw();
|
|
|
|
public:
|
|
|
|
const Fl_Menu_Item* menu;
|
|
|
|
menutitle(int X, int Y, int W, int H, const Fl_Menu_Item*);
|
|
|
|
};
|
|
|
|
|
|
|
|
// each vertical menu has one of these:
|
|
|
|
class menuwindow : public Fl_Menu_Window {
|
|
|
|
void draw();
|
|
|
|
void drawentry(const Fl_Menu_Item*, int i, int erase);
|
|
|
|
public:
|
|
|
|
menutitle* title;
|
|
|
|
int handle(int);
|
|
|
|
int itemheight; // zero == menubar
|
|
|
|
int numitems;
|
|
|
|
int selected;
|
|
|
|
int drawn_selected; // last redraw has this selected
|
|
|
|
const Fl_Menu_Item* menu;
|
|
|
|
menuwindow(const Fl_Menu_Item* m, int X, int Y, int W, int H,
|
|
|
|
const Fl_Menu_Item* picked, const Fl_Menu_Item* title,
|
2002-10-02 20:09:12 +00:00
|
|
|
int menubar = 0, int menubar_title = 0, int right_edge = 0);
|
1998-10-06 18:21:25 +00:00
|
|
|
~menuwindow();
|
|
|
|
void set_selected(int);
|
|
|
|
int find_selected(int mx, int my);
|
|
|
|
int titlex(int);
|
|
|
|
void autoscroll(int);
|
|
|
|
void position(int x, int y);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define LEADING 4 // extra vertical leading
|
|
|
|
|
|
|
|
extern char fl_draw_shortcut;
|
|
|
|
|
|
|
|
// width of label, including effect of & characters:
|
|
|
|
int Fl_Menu_Item::measure(int* hp, const Fl_Menu_* m) const {
|
|
|
|
Fl_Label l;
|
2001-09-04 13:13:29 +00:00
|
|
|
l.value = text;
|
|
|
|
l.image = 0;
|
|
|
|
l.deimage = 0;
|
|
|
|
l.type = labeltype_;
|
|
|
|
l.font = labelsize_ ? labelfont_ : uchar(m ? m->textfont() : FL_HELVETICA);
|
2002-11-19 16:37:36 +00:00
|
|
|
l.size = labelsize_ ? labelsize_ : m ? m->textsize() : (uchar)FL_NORMAL_SIZE;
|
2001-09-04 13:13:29 +00:00
|
|
|
l.color = FL_BLACK; // this makes no difference?
|
1998-10-06 18:21:25 +00:00
|
|
|
fl_draw_shortcut = 1;
|
|
|
|
int w = 0; int h = 0; l.measure(w, hp ? *hp : h);
|
|
|
|
fl_draw_shortcut = 0;
|
|
|
|
if (flags & (FL_MENU_TOGGLE|FL_MENU_RADIO)) w += 14;
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_Menu_Item::draw(int x, int y, int w, int h, const Fl_Menu_* m,
|
|
|
|
int selected) const {
|
|
|
|
Fl_Label l;
|
2001-08-06 03:17:43 +00:00
|
|
|
l.value = text;
|
|
|
|
l.image = 0;
|
|
|
|
l.deimage = 0;
|
|
|
|
l.type = labeltype_;
|
|
|
|
l.font = labelsize_ ? labelfont_ : uchar(m ? m->textfont() : FL_HELVETICA);
|
2002-11-19 16:37:36 +00:00
|
|
|
l.size = labelsize_ ? labelsize_ : m ? m->textsize() : (uchar)FL_NORMAL_SIZE;
|
2001-08-06 03:17:43 +00:00
|
|
|
l.color = labelcolor_ ? labelcolor_ : m ? m->textcolor() : int(FL_BLACK);
|
2001-10-29 03:44:33 +00:00
|
|
|
if (!active()) l.color = fl_inactive((Fl_Color)l.color);
|
1998-10-06 18:21:25 +00:00
|
|
|
Fl_Color color = m ? m->color() : FL_GRAY;
|
|
|
|
if (selected) {
|
|
|
|
Fl_Color r = m ? m->selection_color() : FL_SELECTION_COLOR;
|
|
|
|
Fl_Boxtype b = m && m->down_box() ? m->down_box() : FL_FLAT_BOX;
|
2001-10-29 03:44:33 +00:00
|
|
|
if (fl_contrast(r,color)!=r) { // back compatability boxtypes
|
1998-10-06 18:21:25 +00:00
|
|
|
if (selected == 2) { // menu title
|
|
|
|
r = color;
|
|
|
|
b = m ? m->box() : FL_UP_BOX;
|
|
|
|
} else {
|
|
|
|
r = (Fl_Color)(FL_COLOR_CUBE-1); // white
|
2001-10-29 03:44:33 +00:00
|
|
|
l.color = fl_contrast((Fl_Color)labelcolor_, r);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
} else {
|
2001-10-29 03:44:33 +00:00
|
|
|
l.color = fl_contrast((Fl_Color)labelcolor_, r);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
1999-01-05 17:53:00 +00:00
|
|
|
if (selected == 2) { // menu title
|
1998-10-06 18:21:25 +00:00
|
|
|
fl_draw_box(b, x, y, w, h, r);
|
1998-11-10 14:40:18 +00:00
|
|
|
x += 3;
|
|
|
|
w -= 8;
|
1998-10-06 18:21:25 +00:00
|
|
|
} else {
|
2000-04-12 04:32:05 +00:00
|
|
|
fl_draw_box(b, x+1, y-(LEADING-2)/2, w-2, h+(LEADING-2), r);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & (FL_MENU_TOGGLE|FL_MENU_RADIO)) {
|
2001-12-20 14:41:44 +00:00
|
|
|
int d = (h - FL_NORMAL_SIZE + 1) / 2;
|
|
|
|
int W = h - 2 * d;
|
2001-09-04 13:13:29 +00:00
|
|
|
|
1998-10-06 18:21:25 +00:00
|
|
|
if (flags & FL_MENU_RADIO) {
|
2002-04-29 19:27:51 +00:00
|
|
|
fl_draw_box(FL_ROUND_DOWN_BOX, x+2, y+d, W, W, FL_BACKGROUND2_COLOR);
|
1998-10-06 18:21:25 +00:00
|
|
|
if (value()) {
|
2001-12-20 14:41:44 +00:00
|
|
|
fl_color(labelcolor_);
|
2002-05-03 14:59:31 +00:00
|
|
|
int tW = (W - Fl::box_dw(FL_ROUND_DOWN_BOX)) / 2 + 1;
|
|
|
|
if ((W - tW) & 1) tW++; // Make sure difference is even to center
|
2002-04-29 19:27:51 +00:00
|
|
|
int td = Fl::box_dx(FL_ROUND_DOWN_BOX) + 1;
|
2002-04-30 15:34:58 +00:00
|
|
|
switch (tW) {
|
|
|
|
// Larger circles draw fine...
|
|
|
|
default :
|
|
|
|
fl_pie(x + td + 2, y + d + td, tW, tW, 0.0, 360.0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Small circles don't draw well on many systems...
|
|
|
|
case 6 :
|
|
|
|
fl_rectf(x + td + 4, y + d + td, tW - 4, tW);
|
|
|
|
fl_rectf(x + td + 3, y + d + td + 1, tW - 2, tW - 2);
|
|
|
|
fl_rectf(x + td + 2, y + d + td + 2, tW, tW - 4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5 :
|
|
|
|
case 4 :
|
|
|
|
case 3 :
|
|
|
|
fl_rectf(x + td + 3, y + d + td, tW - 2, tW);
|
|
|
|
fl_rectf(x + td + 2, y + d + td + 1, tW, tW - 2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2 :
|
|
|
|
case 1 :
|
|
|
|
fl_rectf(x + td + 2, y + d + td, tW, tW);
|
|
|
|
break;
|
2001-12-20 14:41:44 +00:00
|
|
|
}
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
} else {
|
2002-04-11 10:46:19 +00:00
|
|
|
fl_draw_box(FL_DOWN_BOX, x+2, y+d, W, W, FL_BACKGROUND2_COLOR);
|
2001-09-04 13:13:29 +00:00
|
|
|
if (value()) {
|
2001-12-20 14:41:44 +00:00
|
|
|
fl_color(labelcolor_);
|
2002-10-11 17:03:47 +00:00
|
|
|
int tx = x + 5;
|
|
|
|
int tw = W - 6;
|
|
|
|
int d1 = tw/3;
|
|
|
|
int d2 = tw-d1;
|
|
|
|
int ty = y + d + (W+d2)/2-d1-2;
|
|
|
|
for (int n = 0; n < 3; n++, ty++) {
|
|
|
|
fl_line(tx, ty, tx+d1, ty+d1);
|
|
|
|
fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1);
|
|
|
|
}
|
2001-09-04 13:13:29 +00:00
|
|
|
}
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
2001-12-20 14:41:44 +00:00
|
|
|
x += W + 3;
|
|
|
|
w -= W + 3;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
1999-03-07 08:51:44 +00:00
|
|
|
if (!fl_draw_shortcut) fl_draw_shortcut = 1;
|
1998-11-10 14:40:18 +00:00
|
|
|
l.draw(x+3, y, w>6 ? w-6 : 0, h, FL_ALIGN_LEFT);
|
1998-10-06 18:21:25 +00:00
|
|
|
fl_draw_shortcut = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
menutitle::menutitle(int X, int Y, int W, int H, const Fl_Menu_Item* L) :
|
|
|
|
Fl_Menu_Window(X, Y, W, H, 0) {
|
|
|
|
end();
|
|
|
|
set_modal();
|
|
|
|
clear_border();
|
|
|
|
menu = L;
|
2003-01-14 17:32:25 +00:00
|
|
|
if (L->labelcolor_ || Fl::scheme() || L->labeltype_ > FL_NO_LABEL) clear_overlay();
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
menuwindow::menuwindow(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp,
|
|
|
|
const Fl_Menu_Item* picked, const Fl_Menu_Item* t,
|
2002-10-02 20:09:12 +00:00
|
|
|
int menubar, int menubar_title, int right_edge)
|
1998-10-06 18:21:25 +00:00
|
|
|
: Fl_Menu_Window(X, Y, Wp, Hp, 0)
|
|
|
|
{
|
2002-10-02 20:09:12 +00:00
|
|
|
if (!right_edge) right_edge = Fl::w();
|
|
|
|
|
1998-10-06 18:21:25 +00:00
|
|
|
end();
|
|
|
|
set_modal();
|
|
|
|
clear_border();
|
|
|
|
menu = m;
|
|
|
|
drawn_selected = -1;
|
2000-04-11 08:11:56 +00:00
|
|
|
if (button) {
|
|
|
|
box(button->box());
|
|
|
|
if (box() == FL_NO_BOX || box() == FL_FLAT_BOX) box(FL_UP_BOX);
|
|
|
|
} else {
|
|
|
|
box(FL_UP_BOX);
|
|
|
|
}
|
2002-03-25 22:11:52 +00:00
|
|
|
color(button && !Fl::scheme() ? button->color() : FL_GRAY);
|
1998-10-06 18:21:25 +00:00
|
|
|
selected = -1;
|
2000-11-20 19:02:20 +00:00
|
|
|
{int j = 0;
|
|
|
|
if (m) for (const Fl_Menu_Item* m1=m; ; m1 = m1->next(), j++) {
|
1998-10-06 18:21:25 +00:00
|
|
|
if (picked) {
|
2000-11-20 19:02:20 +00:00
|
|
|
if (m1 == picked) {selected = j; picked = 0;}
|
|
|
|
else if (m1 > picked) {selected = j-1; picked = 0; Wp = Hp = 0;}
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
if (!m1->text) break;
|
|
|
|
}
|
2000-11-20 19:02:20 +00:00
|
|
|
numitems = j;}
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
if (menubar) {
|
|
|
|
itemheight = 0;
|
|
|
|
title = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
itemheight = 1;
|
|
|
|
|
|
|
|
int hotKeysw = 0;
|
|
|
|
int Wtitle = 0;
|
|
|
|
int Htitle = 0;
|
1998-11-10 14:40:18 +00:00
|
|
|
if (t) Wtitle = t->measure(&Htitle, button) + 12;
|
|
|
|
int W = 0;
|
1998-10-06 18:21:25 +00:00
|
|
|
if (m) for (; m->text; m = m->next()) {
|
2002-08-09 01:09:49 +00:00
|
|
|
int hh; int w1 = m->measure(&hh, button);
|
|
|
|
if (hh+LEADING>itemheight) itemheight = hh+LEADING;
|
1998-10-06 18:21:25 +00:00
|
|
|
if (m->flags&(FL_SUBMENU|FL_SUBMENU_POINTER)) w1 += 14;
|
|
|
|
if (w1 > W) W = w1;
|
|
|
|
if (m->shortcut_) {
|
|
|
|
w1 = int(fl_width(fl_shortcut_label(m->shortcut_))) + 8;
|
|
|
|
if (w1 > hotKeysw) hotKeysw = w1;
|
|
|
|
}
|
2003-01-14 17:32:25 +00:00
|
|
|
if (m->labelcolor_ || Fl::scheme() || m->labeltype_ > FL_NO_LABEL) clear_overlay();
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
if (selected >= 0 && !Wp) X -= W/2;
|
1998-11-10 14:40:18 +00:00
|
|
|
int BW = Fl::box_dx(box());
|
|
|
|
W += hotKeysw+2*BW+7;
|
|
|
|
if (Wp > W) W = Wp;
|
|
|
|
if (Wtitle > W) W = Wtitle;
|
1998-10-06 18:21:25 +00:00
|
|
|
|
2002-10-02 20:09:12 +00:00
|
|
|
if (!Wp) {if (X < 0) X = 0; if (X > Fl::w()-W) X= right_edge-W;}
|
1998-10-06 18:21:25 +00:00
|
|
|
x(X); w(W);
|
2000-04-12 04:32:05 +00:00
|
|
|
h((numitems ? itemheight*numitems-LEADING : 0)+2*BW+3);
|
1998-10-06 18:21:25 +00:00
|
|
|
if (selected >= 0)
|
2000-04-11 08:11:56 +00:00
|
|
|
Y = Y+(Hp-itemheight)/2-selected*itemheight-BW;
|
1998-10-06 18:21:25 +00:00
|
|
|
else
|
|
|
|
Y = Y+Hp;
|
2000-04-11 08:11:56 +00:00
|
|
|
if (m) y(Y); else {y(Y-2); w(1); h(1);}
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
if (t) {
|
2000-04-11 08:11:56 +00:00
|
|
|
int dy = menubar_title ? Fl::box_dy(button->box())+1 : 2;
|
|
|
|
int ht = menubar_title ? button->h()-dy*2 : Htitle+2*BW+3;
|
|
|
|
title = new menutitle(X, Y-ht-dy, Wtitle, ht, t);
|
1998-10-06 18:21:25 +00:00
|
|
|
} else
|
|
|
|
title = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
menuwindow::~menuwindow() {
|
|
|
|
delete title;
|
|
|
|
}
|
|
|
|
|
|
|
|
void menuwindow::position(int X, int Y) {
|
|
|
|
if (title) {title->position(X, title->y()+Y-y());}
|
|
|
|
Fl_Menu_Window::position(X, Y);
|
1998-12-08 21:04:40 +00:00
|
|
|
// x(X); y(Y); // don't wait for response from X
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// scroll so item i is visible on screen
|
2000-11-20 19:02:20 +00:00
|
|
|
void menuwindow::autoscroll(int n) {
|
|
|
|
int Y = y()+Fl::box_dx(box())+2+n*itemheight;
|
1999-02-19 15:34:09 +00:00
|
|
|
if (Y <= Fl::y()) Y = Fl::y()-Y+10;
|
1998-10-06 18:21:25 +00:00
|
|
|
else {
|
1999-02-19 15:34:09 +00:00
|
|
|
Y = Y+itemheight-Fl::h()-Fl::y();
|
1999-01-19 19:12:51 +00:00
|
|
|
if (Y < 0) return;
|
1998-10-06 18:21:25 +00:00
|
|
|
Y = -Y-10;
|
|
|
|
}
|
|
|
|
Fl_Menu_Window::position(x(), y()+Y);
|
1998-12-08 21:04:40 +00:00
|
|
|
// y(y()+Y); // don't wait for response from X
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
2002-08-09 01:09:49 +00:00
|
|
|
void menuwindow::drawentry(const Fl_Menu_Item* m, int n, int eraseit) {
|
1998-10-06 18:21:25 +00:00
|
|
|
if (!m) return; // this happens if -1 is selected item and redrawn
|
|
|
|
|
1998-11-10 14:40:18 +00:00
|
|
|
int BW = Fl::box_dx(box());
|
2002-08-09 01:09:49 +00:00
|
|
|
int xx = BW;
|
|
|
|
int W = w();
|
|
|
|
int ww = W-2*BW-1;
|
|
|
|
int yy = BW+1+n*itemheight;
|
|
|
|
int hh = itemheight - LEADING;
|
1998-10-06 18:21:25 +00:00
|
|
|
|
2002-08-09 01:09:49 +00:00
|
|
|
if (eraseit && n != selected) {
|
2003-05-18 22:12:24 +00:00
|
|
|
if (Fl::scheme()) {
|
|
|
|
fl_push_clip(xx+1, yy-(LEADING-2)/2, ww-2, hh+(LEADING-2));
|
|
|
|
draw_box(box(), 0, 0, w(), h(), color());
|
|
|
|
fl_pop_clip();
|
|
|
|
} else {
|
|
|
|
fl_color(button ? button->color() : FL_GRAY);
|
|
|
|
fl_rectf(xx+1, yy-(LEADING-2)/2, ww-2, hh+(LEADING-2));
|
|
|
|
}
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
2002-08-09 01:09:49 +00:00
|
|
|
m->draw(xx, yy, ww, hh, button, n==selected);
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
// the shortcuts and arrows assumme fl_color() was left set by draw():
|
|
|
|
if (m->submenu()) {
|
2002-08-09 01:09:49 +00:00
|
|
|
int sz = (hh-5)&-2;
|
|
|
|
int y1 = yy+(hh-sz)/2;
|
|
|
|
int x1 = xx+ww-sz-3;
|
2000-04-11 08:11:56 +00:00
|
|
|
fl_polygon(x1, y1, x1, y1+sz, x1+sz, y1+sz/2);
|
1998-10-06 18:21:25 +00:00
|
|
|
} else if (m->shortcut_) {
|
2003-05-21 01:50:14 +00:00
|
|
|
Fl_Font f = m->labelfont_ ? (Fl_Font)m->labelfont_ :
|
|
|
|
button ? button->textfont() : FL_HELVETICA;
|
|
|
|
fl_font(f, m->labelsize_ ? m->labelsize_ :
|
|
|
|
button ? button->textsize() : FL_NORMAL_SIZE);
|
2002-08-09 01:09:49 +00:00
|
|
|
fl_draw(fl_shortcut_label(m->shortcut_), xx, yy, ww-3, hh, FL_ALIGN_RIGHT);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m->flags & FL_MENU_DIVIDER) {
|
|
|
|
fl_color(FL_DARK3);
|
2002-08-09 01:09:49 +00:00
|
|
|
fl_xyline(BW-1, yy+hh+(LEADING-2)/2, W-2*BW+2);
|
1998-10-06 18:21:25 +00:00
|
|
|
fl_color(FL_LIGHT3);
|
2002-08-09 01:09:49 +00:00
|
|
|
fl_xyline(BW-1, yy+hh+((LEADING-2)/2+1), W-2*BW+2);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void menutitle::draw() {
|
|
|
|
menu->draw(0, 0, w(), h(), button, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void menuwindow::draw() {
|
1998-10-19 17:53:09 +00:00
|
|
|
if (damage() != FL_DAMAGE_CHILD) { // complete redraw
|
1998-11-10 14:40:18 +00:00
|
|
|
fl_draw_box(box(), 0, 0, w(), h(), color());
|
1998-10-06 18:21:25 +00:00
|
|
|
if (menu) {
|
2000-11-20 19:02:20 +00:00
|
|
|
const Fl_Menu_Item* m; int j;
|
|
|
|
for (m=menu, j=0; m->text; j++, m = m->next()) drawentry(m, j, 0);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
} else {
|
1998-10-19 17:53:09 +00:00
|
|
|
if (damage() & FL_DAMAGE_CHILD && selected!=drawn_selected) { // change selection
|
1998-10-06 18:21:25 +00:00
|
|
|
drawentry(menu->next(drawn_selected), drawn_selected, 1);
|
|
|
|
drawentry(menu->next(selected), selected, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drawn_selected = selected;
|
|
|
|
}
|
|
|
|
|
2000-11-20 19:02:20 +00:00
|
|
|
void menuwindow::set_selected(int n) {
|
|
|
|
if (n != selected) {selected = n; damage(FL_DAMAGE_CHILD);}
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
int menuwindow::find_selected(int mx, int my) {
|
|
|
|
if (!menu || !menu->text) return -1;
|
|
|
|
mx -= x();
|
|
|
|
my -= y();
|
1998-10-19 21:00:26 +00:00
|
|
|
if (my < 0 || my >= h()) return -1;
|
1998-10-06 18:21:25 +00:00
|
|
|
if (!itemheight) { // menubar
|
2002-08-09 01:09:49 +00:00
|
|
|
int xx = 3; int n = 0;
|
1998-10-06 18:21:25 +00:00
|
|
|
const Fl_Menu_Item* m = menu;
|
2000-11-20 19:02:20 +00:00
|
|
|
for (; ; m = m->next(), n++) {
|
1998-10-06 18:21:25 +00:00
|
|
|
if (!m->text) return -1;
|
2002-08-09 01:09:49 +00:00
|
|
|
xx += m->measure(0, button) + 16;
|
|
|
|
if (xx > mx) break;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
2000-11-20 19:02:20 +00:00
|
|
|
return n;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
1999-01-24 15:27:35 +00:00
|
|
|
if (mx < Fl::box_dx(box()) || mx >= w()) return -1;
|
2000-11-20 19:02:20 +00:00
|
|
|
int n = (my-Fl::box_dx(box())-1)/itemheight;
|
|
|
|
if (n < 0 || n>=numitems) return -1;
|
|
|
|
return n;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
2000-11-20 19:02:20 +00:00
|
|
|
// return horizontal position for item n in a menubar:
|
|
|
|
int menuwindow::titlex(int n) {
|
1998-10-06 18:21:25 +00:00
|
|
|
const Fl_Menu_Item* m;
|
2002-08-09 01:09:49 +00:00
|
|
|
int xx = 3;
|
|
|
|
for (m=menu; n--; m = m->next()) xx += m->measure(0, button) + 16;
|
|
|
|
return xx;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Fl_Menu_Item::popup(...)
|
|
|
|
|
|
|
|
// Because Fl::grab() is done, all events go to one of the menu windows.
|
|
|
|
// But the handle method needs to look at all of them to find out
|
|
|
|
// what item the user is pointing at. And it needs a whole lot
|
|
|
|
// of other state variables to determine what is going on with
|
|
|
|
// the currently displayed menus.
|
|
|
|
// So the main loop (handlemenu()) puts all the state in a structure
|
|
|
|
// and puts a pointer to it in a static location, so the handle()
|
|
|
|
// on menus can refer to it and alter it. The handle() method
|
|
|
|
// changes variables in this state to indicate what item is
|
|
|
|
// picked, but does not actually alter the display, instead the
|
|
|
|
// main loop does that. This is because the X mapping and unmapping
|
|
|
|
// of windows is slow, and we don't want to fall behind the events.
|
|
|
|
|
1999-01-19 19:12:51 +00:00
|
|
|
// values for menustate.state:
|
|
|
|
#define INITIAL_STATE 0 // no mouse up or down since popup() called
|
|
|
|
#define PUSH_STATE 1 // mouse has been pushed on a normal item
|
|
|
|
#define DONE_STATE 2 // exit the popup, the current item was picked
|
|
|
|
#define MENU_PUSH_STATE 3 // mouse has been pushed on a menu title
|
|
|
|
|
1998-10-06 18:21:25 +00:00
|
|
|
struct menustate {
|
|
|
|
const Fl_Menu_Item* current_item; // what mouse is pointing at
|
|
|
|
int menu_number; // which menu it is in
|
1999-04-26 06:45:29 +00:00
|
|
|
int item_number; // which item in that menu, -1 if none
|
1998-10-06 18:21:25 +00:00
|
|
|
menuwindow* p[20]; // pointers to menus
|
|
|
|
int nummenus;
|
|
|
|
int menubar; // if true p[0] is a menubar
|
1999-01-19 19:12:51 +00:00
|
|
|
int state;
|
1998-10-06 18:21:25 +00:00
|
|
|
};
|
|
|
|
static menustate* p;
|
|
|
|
|
|
|
|
static inline void setitem(const Fl_Menu_Item* i, int m, int n) {
|
|
|
|
p->current_item = i;
|
|
|
|
p->menu_number = m;
|
|
|
|
p->item_number = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setitem(int m, int n) {
|
2002-08-09 01:09:49 +00:00
|
|
|
menustate &pp = *p;
|
|
|
|
pp.current_item = (n >= 0) ? pp.p[m]->menu->next(n) : 0;
|
|
|
|
pp.menu_number = m;
|
|
|
|
pp.item_number = n;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int forward(int menu) { // go to next item in menu menu if possible
|
2002-08-09 01:09:49 +00:00
|
|
|
menustate &pp = *p;
|
|
|
|
menuwindow &m = *(pp.p[menu]);
|
|
|
|
int item = (menu == pp.menu_number) ? pp.item_number : m.selected;
|
1998-10-06 18:21:25 +00:00
|
|
|
while (++item < m.numitems) {
|
|
|
|
const Fl_Menu_Item* m1 = m.menu->next(item);
|
|
|
|
if (m1->activevisible()) {setitem(m1, menu, item); return 1;}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int backward(int menu) { // previous item in menu menu if possible
|
2002-08-09 01:09:49 +00:00
|
|
|
menustate &pp = *p;
|
|
|
|
menuwindow &m = *(pp.p[menu]);
|
|
|
|
int item = (menu == pp.menu_number) ? pp.item_number : m.selected;
|
1999-04-26 06:45:29 +00:00
|
|
|
if (item < 0) item = m.numitems;
|
1998-10-06 18:21:25 +00:00
|
|
|
while (--item >= 0) {
|
|
|
|
const Fl_Menu_Item* m1 = m.menu->next(item);
|
|
|
|
if (m1->activevisible()) {setitem(m1, menu, item); return 1;}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int menuwindow::handle(int e) {
|
2002-08-09 01:09:49 +00:00
|
|
|
menustate &pp = *p;
|
1998-10-06 18:21:25 +00:00
|
|
|
switch (e) {
|
|
|
|
case FL_KEYBOARD:
|
|
|
|
switch (Fl::event_key()) {
|
1999-04-26 06:45:29 +00:00
|
|
|
case FL_BackSpace:
|
|
|
|
case 0xFE20: // backtab
|
|
|
|
BACKTAB:
|
2002-08-09 01:09:49 +00:00
|
|
|
if (!backward(pp.menu_number)) {pp.item_number = -1;backward(pp.menu_number);}
|
1999-04-26 06:45:29 +00:00
|
|
|
return 1;
|
1998-10-06 18:21:25 +00:00
|
|
|
case FL_Up:
|
2002-11-19 16:37:36 +00:00
|
|
|
if (pp.menubar && pp.menu_number == 0) {
|
|
|
|
// Do nothing...
|
|
|
|
} else if (backward(pp.menu_number)) {
|
|
|
|
// Do nothing...
|
|
|
|
} else if (pp.menubar && pp.menu_number==1) {
|
|
|
|
setitem(0, pp.p[0]->selected);
|
|
|
|
}
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
2002-11-08 15:57:10 +00:00
|
|
|
case FL_Tab:
|
|
|
|
if (Fl::event_shift()) goto BACKTAB;
|
1998-10-06 18:21:25 +00:00
|
|
|
case FL_Down:
|
2002-08-09 01:09:49 +00:00
|
|
|
if (pp.menu_number || !pp.menubar) forward(pp.menu_number);
|
|
|
|
else if (pp.menu_number < pp.nummenus-1) forward(pp.menu_number+1);
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
case FL_Right:
|
2002-08-09 01:09:49 +00:00
|
|
|
if (pp.menubar && (pp.menu_number<=0 || pp.menu_number==1 && pp.nummenus==2))
|
1998-10-06 18:21:25 +00:00
|
|
|
forward(0);
|
2002-08-09 01:09:49 +00:00
|
|
|
else if (pp.menu_number < pp.nummenus-1) forward(pp.menu_number+1);
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
case FL_Left:
|
2002-08-09 01:09:49 +00:00
|
|
|
if (pp.menubar && pp.menu_number<=1) backward(0);
|
|
|
|
else if (pp.menu_number>0)
|
|
|
|
setitem(pp.menu_number-1, pp.p[pp.menu_number-1]->selected);
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
case FL_Enter:
|
2001-08-04 20:17:10 +00:00
|
|
|
case ' ':
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.state = DONE_STATE;
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
case FL_Escape:
|
|
|
|
setitem(0, -1, 0);
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.state = DONE_STATE;
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FL_SHORTCUT: {
|
2002-08-09 01:09:49 +00:00
|
|
|
for (int mymenu = pp.nummenus; mymenu--;) {
|
|
|
|
menuwindow &mw = *(pp.p[mymenu]);
|
1998-10-06 18:21:25 +00:00
|
|
|
int item; const Fl_Menu_Item* m = mw.menu->find_shortcut(&item);
|
|
|
|
if (m) {
|
2000-11-20 19:02:20 +00:00
|
|
|
setitem(m, mymenu, item);
|
2002-08-09 01:09:49 +00:00
|
|
|
if (!m->submenu()) pp.state = DONE_STATE;
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}} break;
|
2002-05-16 07:43:59 +00:00
|
|
|
case FL_ENTER:
|
2002-05-15 23:12:30 +00:00
|
|
|
case FL_MOVE:
|
2002-05-16 07:43:59 +00:00
|
|
|
case FL_PUSH:
|
1998-10-06 18:21:25 +00:00
|
|
|
case FL_DRAG: {
|
|
|
|
int mx = Fl::event_x_root();
|
|
|
|
int my = Fl::event_y_root();
|
2000-11-20 19:02:20 +00:00
|
|
|
int item=0; int mymenu;
|
2002-08-09 01:09:49 +00:00
|
|
|
for (mymenu = pp.nummenus-1; ; mymenu--) {
|
|
|
|
item = pp.p[mymenu]->find_selected(mx, my);
|
1998-10-06 18:21:25 +00:00
|
|
|
if (item >= 0) break;
|
2000-11-20 19:02:20 +00:00
|
|
|
if (mymenu <= 0) break;
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
2003-05-21 01:37:17 +00:00
|
|
|
if (my == 0 && item > 0) setitem(mymenu, item - 1);
|
|
|
|
else setitem(mymenu, item);
|
1998-10-06 18:21:25 +00:00
|
|
|
if (e == FL_PUSH) {
|
2002-08-09 01:09:49 +00:00
|
|
|
if (pp.current_item && pp.current_item->submenu() // this is a menu title
|
|
|
|
&& item != pp.p[mymenu]->selected // and it is not already on
|
|
|
|
&& !pp.current_item->callback_) // and it does not have a callback
|
|
|
|
pp.state = MENU_PUSH_STATE;
|
1999-01-19 19:12:51 +00:00
|
|
|
else
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.state = PUSH_STATE;
|
1999-01-19 19:12:51 +00:00
|
|
|
}} return 1;
|
1998-10-06 18:21:25 +00:00
|
|
|
case FL_RELEASE:
|
1999-01-19 19:12:51 +00:00
|
|
|
// do nothing if they try to pick inactive items
|
2002-08-09 01:09:49 +00:00
|
|
|
if (pp.current_item && !pp.current_item->activevisible()) return 1;
|
1999-01-19 19:12:51 +00:00
|
|
|
// Mouse must either be held down/dragged some, or this must be
|
|
|
|
// the second click (not the one that popped up the menu):
|
2002-08-09 01:09:49 +00:00
|
|
|
if (!Fl::event_is_click() || pp.state == PUSH_STATE ||
|
|
|
|
pp.menubar && pp.current_item && !pp.current_item->submenu() // button
|
1999-08-09 06:19:33 +00:00
|
|
|
) {
|
|
|
|
#if 0 // makes the check/radio items leave the menu up
|
2002-08-09 01:09:49 +00:00
|
|
|
const Fl_Menu_Item* m = pp.current_item;
|
1999-08-09 06:19:33 +00:00
|
|
|
if (m && button && (m->flags & (FL_MENU_TOGGLE|FL_MENU_RADIO))) {
|
|
|
|
((Fl_Menu_*)button)->picked(m);
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.p[pp.menu_number]->redraw();
|
1999-08-09 06:19:33 +00:00
|
|
|
} else
|
|
|
|
#endif
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.state = DONE_STATE;
|
1999-08-09 06:19:33 +00:00
|
|
|
}
|
1998-10-06 18:21:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return Fl_Window::handle(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Fl_Menu_Item* Fl_Menu_Item::pulldown(
|
|
|
|
int X, int Y, int W, int H,
|
|
|
|
const Fl_Menu_Item* initial_item,
|
|
|
|
const Fl_Menu_* pbutton,
|
|
|
|
const Fl_Menu_Item* t,
|
|
|
|
int menubar) const
|
|
|
|
{
|
|
|
|
Fl_Group::current(0); // fix possible user error...
|
|
|
|
|
|
|
|
button = pbutton;
|
|
|
|
if (pbutton) {
|
|
|
|
for (Fl_Window* w = pbutton->window(); w; w = w->window()) {
|
|
|
|
X += w->x();
|
|
|
|
Y += w->y();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
X += Fl::event_x_root()-Fl::event_x();
|
|
|
|
Y += Fl::event_y_root()-Fl::event_y();
|
|
|
|
}
|
|
|
|
menuwindow mw(this, X, Y, W, H, initial_item, t, menubar);
|
|
|
|
Fl::grab(mw);
|
2002-08-09 01:09:49 +00:00
|
|
|
menustate pp; p = &pp;
|
|
|
|
pp.p[0] = &mw;
|
|
|
|
pp.nummenus = 1;
|
|
|
|
pp.menubar = menubar;
|
|
|
|
pp.state = INITIAL_STATE;
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
menuwindow* fakemenu = 0; // kludge for buttons in menubar
|
|
|
|
|
|
|
|
// preselected item, pop up submenus if necessary:
|
|
|
|
if (initial_item && mw.selected >= 0) {
|
|
|
|
setitem(0, mw.selected);
|
|
|
|
goto STARTUP;
|
|
|
|
}
|
|
|
|
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.current_item = 0; pp.menu_number = 0; pp.item_number = -1;
|
1998-10-06 18:21:25 +00:00
|
|
|
if (menubar) mw.handle(FL_DRAG); // find the initial menu
|
2002-08-09 01:09:49 +00:00
|
|
|
initial_item = pp.current_item;
|
1998-10-06 18:21:25 +00:00
|
|
|
if (initial_item) goto STARTUP;
|
|
|
|
|
1999-01-19 19:12:51 +00:00
|
|
|
// the main loop, runs until p.state goes to DONE_STATE:
|
1998-10-06 18:21:25 +00:00
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
// make sure all the menus are shown:
|
2002-08-09 01:09:49 +00:00
|
|
|
{for (int k = menubar; k < pp.nummenus; k++)
|
|
|
|
if (!pp.p[k]->shown()) {
|
|
|
|
if (pp.p[k]->title) pp.p[k]->title->show();
|
|
|
|
pp.p[k]->show();
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get events:
|
2002-08-09 01:09:49 +00:00
|
|
|
{const Fl_Menu_Item* oldi = pp.current_item;
|
1998-10-06 18:21:25 +00:00
|
|
|
Fl::wait();
|
2002-08-09 01:09:49 +00:00
|
|
|
if (pp.state == DONE_STATE) break; // done.
|
|
|
|
if (pp.current_item == oldi) continue;}
|
1998-10-06 18:21:25 +00:00
|
|
|
// only do rest if item changes:
|
|
|
|
|
|
|
|
delete fakemenu; fakemenu = 0; // turn off "menubar button"
|
|
|
|
|
2002-08-09 01:09:49 +00:00
|
|
|
if (!pp.current_item) { // pointing at nothing
|
1998-10-06 18:21:25 +00:00
|
|
|
// turn off selection in deepest menu, but don't erase other menus:
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.p[pp.nummenus-1]->set_selected(-1);
|
1998-10-06 18:21:25 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete fakemenu; fakemenu = 0;
|
|
|
|
initial_item = 0; // stop the startup code
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.p[pp.menu_number]->autoscroll(pp.item_number);
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
STARTUP:
|
2002-08-09 01:09:49 +00:00
|
|
|
menuwindow& cw = *pp.p[pp.menu_number];
|
|
|
|
const Fl_Menu_Item* m = pp.current_item;
|
1998-10-06 18:21:25 +00:00
|
|
|
if (!m->activevisible()) { // pointing at inactive item
|
|
|
|
cw.set_selected(-1);
|
|
|
|
initial_item = 0; // turn off startup code
|
|
|
|
continue;
|
|
|
|
}
|
2002-08-09 01:09:49 +00:00
|
|
|
cw.set_selected(pp.item_number);
|
1998-10-06 18:21:25 +00:00
|
|
|
|
|
|
|
if (m==initial_item) initial_item=0; // stop the startup code if item found
|
|
|
|
if (m->submenu()) {
|
|
|
|
const Fl_Menu_Item* title = m;
|
|
|
|
const Fl_Menu_Item* menutable;
|
|
|
|
if (m->flags&FL_SUBMENU) menutable = m+1;
|
|
|
|
else menutable = (Fl_Menu_Item*)(m)->user_data_;
|
|
|
|
// figure out where new menu goes:
|
|
|
|
int nX, nY;
|
2002-08-09 01:09:49 +00:00
|
|
|
if (!pp.menu_number && pp.menubar) { // menu off a menubar:
|
|
|
|
nX = cw.x() + cw.titlex(pp.item_number);
|
1998-10-06 18:21:25 +00:00
|
|
|
nY = cw.y() + cw.h();
|
|
|
|
initial_item = 0;
|
|
|
|
} else {
|
|
|
|
nX = cw.x() + cw.w();
|
2002-08-09 01:09:49 +00:00
|
|
|
nY = cw.y() + pp.item_number * cw.itemheight;
|
1998-10-06 18:21:25 +00:00
|
|
|
title = 0;
|
|
|
|
}
|
|
|
|
if (initial_item) { // bring up submenu containing initial item:
|
2002-10-02 20:09:12 +00:00
|
|
|
menuwindow* n = new menuwindow(menutable,X,Y,W,H,initial_item,title,0,0,cw.x());
|
2002-08-09 01:09:49 +00:00
|
|
|
pp.p[pp.nummenus++] = n;
|
1998-10-06 18:21:25 +00:00
|
|
|
// move all earlier menus to line up with this new one:
|
|
|
|
if (n->selected>=0) {
|
|
|
|
int dy = n->y()-nY;
|
|
|
|
int dx = n->x()-nX;
|
2002-08-09 01:09:49 +00:00
|
|
|
for (int menu = 0; menu <= pp.menu_number; menu++) {
|
|
|
|
menuwindow* tt = pp.p[menu];
|
|
|
|
int nx = tt->x()+dx; if (nx < 0) {nx = 0; dx = -tt->x();}
|
|
|
|
int ny = tt->y()+dy; if (ny < 0) {ny = 0; dy = -tt->y();}
|
|
|
|
tt->position(nx, ny);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
2002-08-09 01:09:49 +00:00
|
|
|
setitem(pp.nummenus-1, n->selected);
|
1998-10-06 18:21:25 +00:00
|
|
|
goto STARTUP;
|
|
|
|
}
|
2002-08-09 01:09:49 +00:00
|
|
|
} else if (pp.nummenus > pp.menu_number+1 &&
|
|
|
|
pp.p[pp.menu_number+1]->menu == menutable) {
|
1998-10-06 18:21:25 +00:00
|
|
|
// the menu is already up:
|
2002-08-09 01:09:49 +00:00
|
|
|
while (pp.nummenus > pp.menu_number+2) delete pp.p[--pp.nummenus];
|
|
|
|
pp.p[pp.nummenus-1]->set_selected(-1);
|
1998-10-06 18:21:25 +00:00
|
|
|
} else {
|
|
|
|
// delete all the old menus and create new one:
|
2002-08-09 01:09:49 +00:00
|
|
|
while (pp.nummenus > pp.menu_number+1) delete pp.p[--pp.nummenus];
|
|
|
|
pp.p[pp.nummenus++]= new menuwindow(menutable, nX, nY,
|
2002-10-02 20:09:12 +00:00
|
|
|
title?1:0, 0, 0, title, 0, menubar, cw.x());
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
} else { // !m->submenu():
|
2002-08-09 01:09:49 +00:00
|
|
|
while (pp.nummenus > pp.menu_number+1) delete pp.p[--pp.nummenus];
|
|
|
|
if (!pp.menu_number && pp.menubar) {
|
1998-10-06 18:21:25 +00:00
|
|
|
// kludge so "menubar buttons" turn "on" by using menu title:
|
|
|
|
fakemenu = new menuwindow(0,
|
2002-08-09 01:09:49 +00:00
|
|
|
cw.x()+cw.titlex(pp.item_number),
|
1998-10-06 18:21:25 +00:00
|
|
|
cw.y()+cw.h(), 0, 0,
|
1999-02-25 19:09:11 +00:00
|
|
|
0, m, 0, 1);
|
1998-10-06 18:21:25 +00:00
|
|
|
fakemenu->title->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-09 01:09:49 +00:00
|
|
|
const Fl_Menu_Item* m = pp.current_item;
|
1998-10-06 18:21:25 +00:00
|
|
|
delete fakemenu;
|
2002-08-09 01:09:49 +00:00
|
|
|
while (pp.nummenus>1) delete pp.p[--pp.nummenus];
|
1998-10-06 18:21:25 +00:00
|
|
|
mw.hide();
|
|
|
|
Fl::release();
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Fl_Menu_Item*
|
|
|
|
Fl_Menu_Item::popup(
|
|
|
|
int X, int Y,
|
|
|
|
const char* title,
|
|
|
|
const Fl_Menu_Item* picked,
|
2002-08-09 01:09:49 +00:00
|
|
|
const Fl_Menu_* but
|
1998-10-06 18:21:25 +00:00
|
|
|
) const
|
|
|
|
{
|
|
|
|
static Fl_Menu_Item dummy; // static so it is all zeros
|
|
|
|
dummy.text = title;
|
2002-08-09 01:09:49 +00:00
|
|
|
return pulldown(X, Y, 0, 0, picked, but, title ? &dummy : 0);
|
1998-10-06 18:21:25 +00:00
|
|
|
}
|
|
|
|
|
2000-07-30 00:31:44 +00:00
|
|
|
// Search only the top level menu for a shortcut. Either &x in the
|
|
|
|
// label or the shortcut fields are used:
|
|
|
|
const Fl_Menu_Item* Fl_Menu_Item::find_shortcut(int* ip) const {
|
|
|
|
const Fl_Menu_Item* m = this;
|
|
|
|
if (m) for (int ii = 0; m->text; m = m->next(), ii++) {
|
|
|
|
if (m->activevisible()) {
|
|
|
|
if (Fl::test_shortcut(m->shortcut_)
|
|
|
|
|| Fl_Widget::test_shortcut(m->text)) {
|
|
|
|
if (ip) *ip=ii;
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursive search of all submenus for anything with this key as a
|
|
|
|
// shortcut. Only uses the shortcut field, ignores &x in the labels:
|
1998-10-06 18:21:25 +00:00
|
|
|
const Fl_Menu_Item* Fl_Menu_Item::test_shortcut() const {
|
|
|
|
const Fl_Menu_Item* m = this;
|
|
|
|
const Fl_Menu_Item* ret = 0;
|
|
|
|
if (m) for (; m->text; m = m->next()) {
|
|
|
|
if (m->activevisible()) {
|
|
|
|
// return immediately any match of an item in top level menu:
|
|
|
|
if (Fl::test_shortcut(m->shortcut_)) return m;
|
|
|
|
// if (Fl_Widget::test_shortcut(m->text)) return m;
|
|
|
|
// only return matches from lower menu if nothing found in top menu:
|
|
|
|
if (!ret && m->submenu()) {
|
|
|
|
const Fl_Menu_Item* s =
|
|
|
|
(m->flags&FL_SUBMENU) ? m+1:(const Fl_Menu_Item*)m->user_data_;
|
|
|
|
ret = s->test_shortcut();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
1998-10-19 20:46:58 +00:00
|
|
|
//
|
2003-05-21 01:50:14 +00:00
|
|
|
// End of "$Id: Fl_Menu.cxx,v 1.18.2.12.2.26 2003/05/21 01:50:13 easysw Exp $".
|
1998-10-19 20:46:58 +00:00
|
|
|
//
|