mirror of
https://github.com/fltk/fltk.git
synced 2025-12-06 10:12:13 +08:00
Declutter draw and handle methods.
Refactoring long methods into smaller parts that are easier to understand.
This commit is contained in:
499
src/Fl_Menu.cxx
499
src/Fl_Menu.cxx
@@ -126,7 +126,25 @@ struct Menu_State
|
||||
bool next_item(menu_index_t menu);
|
||||
|
||||
// handle FL_SHORTCUT in any of the menu windows
|
||||
bool handle_shortcut();
|
||||
int handle_shortcut();
|
||||
|
||||
// move menu item selection left
|
||||
int handle_left();
|
||||
|
||||
// move menu item selection right
|
||||
int handle_right();
|
||||
|
||||
// handle activation of the selected menu item
|
||||
int handle_select();
|
||||
|
||||
// handle menu cancellation
|
||||
int handle_cancel();
|
||||
|
||||
// handle any keyboard event from the menu windows
|
||||
int handle_keyboard_event();
|
||||
|
||||
// handle all mouse events from the menu windows
|
||||
int handle_mouse_events(int e);
|
||||
};
|
||||
|
||||
// Global state of menu windows and popup windows.
|
||||
@@ -220,6 +238,15 @@ class Menu_Window : public Menu_Window_Basetype
|
||||
// Draw a single menu item in this window
|
||||
void draw_entry(const Fl_Menu_Item*, int i, int erase);
|
||||
|
||||
// Draw the submenu arrow
|
||||
void draw_submenu_arrow(const Fl_Rect& bbox);
|
||||
|
||||
// Draw the benu item shortcut text.
|
||||
void draw_shortcut(const Fl_Rect& bbox, const Fl_Menu_Item* mi);
|
||||
|
||||
// Draw the menu item divider.
|
||||
void draw_divider(const Fl_Rect& bbox);
|
||||
|
||||
// Main event handler
|
||||
int handle_part1(int);
|
||||
|
||||
@@ -308,8 +335,8 @@ public:
|
||||
//
|
||||
|
||||
/* Find out if any menu window is under the mouse.
|
||||
\return 1 if the coordinates are inside any of the menuwindows
|
||||
*/
|
||||
\return 1 if the coordinates are inside any of the menuwindows
|
||||
*/
|
||||
bool Menu_State::is_inside(int mx, int my) {
|
||||
for (menu_index_t i=num_menus-1; i>=0; i--) {
|
||||
if (menu_window[i]->is_inside(mx, my)) {
|
||||
@@ -320,10 +347,10 @@ bool Menu_State::is_inside(int mx, int my) {
|
||||
}
|
||||
|
||||
/* Remember this item in the state machine.
|
||||
\param[in] i current menu item
|
||||
\param[in] m index into menu window array
|
||||
\param[in] n index into visible item in that menu window
|
||||
*/
|
||||
\param[in] i current menu item
|
||||
\param[in] m index into menu window array
|
||||
\param[in] n index into visible item in that menu window
|
||||
*/
|
||||
void Menu_State::set_current_item(const Fl_Menu_Item* i, menu_index_t m, item_index_t n) {
|
||||
current_item = i;
|
||||
current_menu_ix = m;
|
||||
@@ -333,7 +360,7 @@ void Menu_State::set_current_item(const Fl_Menu_Item* i, menu_index_t m, item_in
|
||||
/* Find and store a menu item in the state machine.
|
||||
\param[in] m index into menu window array
|
||||
\param[in] n index into visible item in that menu window
|
||||
*/
|
||||
*/
|
||||
void Menu_State::set_current_item(menu_index_t m, item_index_t n) {
|
||||
current_item = (n >= 0) ? menu_window[m]->menu->next(n) : 0;
|
||||
current_menu_ix = m;
|
||||
@@ -344,7 +371,7 @@ void Menu_State::set_current_item(menu_index_t m, item_index_t n) {
|
||||
If the event button is FL_Down, increment once, else go to the bottom of the menu.
|
||||
\param[in] menu index into menu window list
|
||||
\return `true` if an item was found, `false` if the menu wrapped
|
||||
*/
|
||||
*/
|
||||
bool Menu_State::next_item(menu_index_t menu) { // go to next item in menu menu if possible
|
||||
// `menu` is -1 if no item is currently selected, so use the first menu
|
||||
if (menu < 0)
|
||||
@@ -369,10 +396,10 @@ bool Menu_State::next_item(menu_index_t menu) { // go to next item in menu menu
|
||||
}
|
||||
|
||||
/* Go up to the previous selectable menu item.
|
||||
If the event button is FL_Up, decrement once, else go to the top of the menu.
|
||||
\param[in] menu index into menu window list
|
||||
\return `true` if an item was found, `false` if the menu wrapped
|
||||
*/
|
||||
If the event button is FL_Up, decrement once, else go to the top of the menu.
|
||||
\param[in] menu index into menu window list
|
||||
\return `true` if an item was found, `false` if the menu wrapped
|
||||
*/
|
||||
bool Menu_State::prev_item(menu_index_t menu) { // previous item in menu menu if possible
|
||||
// `menu` is -1 if no item is currently selected, so use the first menu
|
||||
if (menu < 0)
|
||||
@@ -397,9 +424,9 @@ bool Menu_State::prev_item(menu_index_t menu) { // previous item in menu menu if
|
||||
}
|
||||
|
||||
/* Handle the FL_SHORTCUT event.
|
||||
\return true if the shortcut was found in the menu and handled.
|
||||
*/
|
||||
bool Menu_State::handle_shortcut() {
|
||||
\return 1 if the shortcut was found in the menu and handled.
|
||||
*/
|
||||
int Menu_State::handle_shortcut() {
|
||||
for (menu_index_t mymenu = num_menus; mymenu--;) {
|
||||
Menu_Window &mw = *(menu_window[mymenu]);
|
||||
int item;
|
||||
@@ -408,10 +435,194 @@ bool Menu_State::handle_shortcut() {
|
||||
set_current_item(m, mymenu, item);
|
||||
if (!m->submenu())
|
||||
state = State::DONE;
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move menu item selection left.
|
||||
\return 1
|
||||
*/
|
||||
int Menu_State::handle_left() {
|
||||
if (in_menubar && current_menu_ix<=1) {
|
||||
prev_item(0);
|
||||
} else if (current_menu_ix>0) {
|
||||
set_current_item(current_menu_ix-1, menu_window[current_menu_ix-1]->selected);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Move menu item selection right.
|
||||
\return 1
|
||||
*/
|
||||
int Menu_State::handle_right() {
|
||||
if (in_menubar && (current_menu_ix<=0 || (current_menu_ix == num_menus-1))) {
|
||||
next_item(0);
|
||||
} else if (current_menu_ix < num_menus-1) {
|
||||
next_item(current_menu_ix+1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle activation of the selected menu item.
|
||||
\return 1
|
||||
*/
|
||||
int Menu_State::handle_select() {
|
||||
// if the current item is a submenu with no callback,
|
||||
// simulate FL_Right to enter the submenu
|
||||
if ( current_item
|
||||
&& (!in_menubar || current_menu_ix > 0)
|
||||
&& current_item->selectable()
|
||||
&& current_item->submenu()
|
||||
&& !current_item->callback_)
|
||||
{
|
||||
return handle_right();
|
||||
}
|
||||
// Ignore keypresses over inactive items, mark KEYBOARD event as used.
|
||||
if (current_item && !current_item->selectable())
|
||||
return 1;
|
||||
// Mark the menu 'done' which will trigger the callback
|
||||
state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle menu cancellation.
|
||||
\return 1
|
||||
*/
|
||||
int Menu_State::handle_cancel() {
|
||||
set_current_item(0, -1, 0);
|
||||
state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle any keyboard event from the menu windows.
|
||||
\return 1 if the keyboard event was handled, else 0
|
||||
*/
|
||||
int Menu_State::handle_keyboard_event() {
|
||||
switch (Fl::event_key()) {
|
||||
case FL_BackSpace:
|
||||
prev_item(current_menu_ix);
|
||||
return 1;
|
||||
case FL_Up:
|
||||
if (in_menubar && current_menu_ix == 0) {
|
||||
// Do nothing...
|
||||
} else if (prev_item(current_menu_ix)) {
|
||||
// Do nothing...
|
||||
} else if (in_menubar && current_menu_ix==1) {
|
||||
set_current_item(0, menu_window[0]->selected);
|
||||
}
|
||||
return 1;
|
||||
case FL_Tab:
|
||||
if (Fl::event_shift()) {
|
||||
prev_item(current_menu_ix);
|
||||
return 1;
|
||||
}
|
||||
if (in_menubar && current_menu_ix == 0)
|
||||
return handle_right();
|
||||
/* FALLTHROUGH */
|
||||
case FL_Down:
|
||||
if (current_menu_ix || !in_menubar) {
|
||||
next_item(current_menu_ix);
|
||||
} else if (current_menu_ix < num_menus-1) {
|
||||
next_item(current_menu_ix+1);
|
||||
}
|
||||
return 1;
|
||||
case FL_Right:
|
||||
return handle_right();
|
||||
case FL_Left:
|
||||
return handle_left();
|
||||
case FL_Enter:
|
||||
case FL_KP_Enter:
|
||||
case ' ':
|
||||
return handle_select();
|
||||
case FL_Escape:
|
||||
return handle_cancel();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle all mouse events from the menu windows.
|
||||
\return 1 if the event was handled, else 0
|
||||
*/
|
||||
int Menu_State::handle_mouse_events(int e) {
|
||||
switch (e) {
|
||||
case FL_MOVE: {
|
||||
static int use_part1_extra = Fl::screen_driver()->need_menu_handle_part1_extra();
|
||||
if (use_part1_extra && state == State::DONE) {
|
||||
return 1; // Fix for STR #2619
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case FL_ENTER:
|
||||
case FL_PUSH:
|
||||
case FL_DRAG:
|
||||
{
|
||||
int mx = Fl::event_x_root();
|
||||
int my = Fl::event_y_root();
|
||||
item_index_t item = 0;
|
||||
menu_index_t mymenu = num_menus-1;
|
||||
// Clicking or dragging outside menu cancels it...
|
||||
if ((!in_menubar || mymenu) && !is_inside(mx, my)) {
|
||||
set_current_item(0, -1, 0);
|
||||
if (e==FL_PUSH)
|
||||
state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
for (mymenu = num_menus-1; ; mymenu--) {
|
||||
item = menu_window[mymenu]->find_selected(mx, my);
|
||||
if (item >= 0)
|
||||
break;
|
||||
if (mymenu <= 0) {
|
||||
// buttons in menubars must be deselected if we move outside of them!
|
||||
if (current_menu_ix==-1 && e==FL_PUSH) {
|
||||
state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
if (current_item && current_menu_ix==0 && !current_item->submenu()) {
|
||||
if (e==FL_PUSH) {
|
||||
state = State::DONE;
|
||||
set_current_item(0, -1, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// all others can stay selected
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
set_current_item(mymenu, item);
|
||||
if (e == FL_PUSH) {
|
||||
if (current_item && current_item->submenu() // this is a menu title
|
||||
&& item != menu_window[mymenu]->selected // and it is not already on
|
||||
&& !current_item->callback_) // and it does not have a callback
|
||||
state = State::MENU_PUSHED;
|
||||
else
|
||||
state = State::PUSHED;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
case FL_RELEASE:
|
||||
// Mouse must either be held down/dragged some, or this must be
|
||||
// the second click (not the one that popped up the menu):
|
||||
if ( !Fl::event_is_click()
|
||||
|| state == State::PUSHED
|
||||
|| (in_menubar && current_item && !current_item->submenu()) // button
|
||||
) {
|
||||
#if 0 // makes the check/radio items leave the menu up
|
||||
const Fl_Menu_Item* m = current_item;
|
||||
if (m && button && (m->flags & (FL_MENU_TOGGLE|FL_MENU_RADIO))) {
|
||||
((Fl_Menu_*)button)->picked(m);
|
||||
p[menu_number]->redraw();
|
||||
} else
|
||||
#endif
|
||||
// do nothing if they try to pick an inactive item, or a submenu with no callback
|
||||
if (!current_item || (current_item->selectable() &&
|
||||
(!current_item->submenu() || current_item->callback_ || (in_menubar && current_menu_ix <= 0))))
|
||||
state = State::DONE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -427,7 +638,8 @@ int Menu_Window::display_height_ = 0;
|
||||
Construct a menu window that can render a list of menu items.
|
||||
\param[in] m pointer to the first menu item in the array
|
||||
\param[in] X, Y position relative to parent_
|
||||
\param[in] Wp, Hp initial minimum size
|
||||
\param[in] Wp, Hp initial minimum size; if Wp is 0, the window will open on the
|
||||
screen with X and Y, else it will open in the screen with the mouse pointer.
|
||||
\param[in] picked pointer to the currently picked menu item, can be nullptr
|
||||
\param[in] t pointer to the menutitle window
|
||||
\param[in] in_menubar set if part of an Fl_Menu_Bar menu
|
||||
@@ -474,7 +686,8 @@ Menu_Window::Menu_Window(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp,
|
||||
}
|
||||
if (!m1->text) break;
|
||||
}
|
||||
num_items = j;}
|
||||
num_items = j;
|
||||
}
|
||||
|
||||
if (in_menubar) {
|
||||
item_height = 0;
|
||||
@@ -631,147 +844,18 @@ int Menu_Window::handle_part1(int e) {
|
||||
Menu_State &pp = *menu_state;
|
||||
switch (e) {
|
||||
case FL_KEYBOARD:
|
||||
switch (Fl::event_key()) {
|
||||
case FL_BackSpace:
|
||||
BACKTAB:
|
||||
menu_state->prev_item(pp.current_menu_ix);
|
||||
return 1;
|
||||
case FL_Up:
|
||||
if (pp.in_menubar && pp.current_menu_ix == 0) {
|
||||
// Do nothing...
|
||||
} else if (menu_state->prev_item(pp.current_menu_ix)) {
|
||||
// Do nothing...
|
||||
} else if (pp.in_menubar && pp.current_menu_ix==1) {
|
||||
menu_state->set_current_item(0, pp.menu_window[0]->selected);
|
||||
}
|
||||
return 1;
|
||||
case FL_Tab:
|
||||
if (Fl::event_shift()) goto BACKTAB;
|
||||
if (pp.in_menubar && pp.current_menu_ix == 0) goto RIGHT;
|
||||
case FL_Down:
|
||||
if (pp.current_menu_ix || !pp.in_menubar) {
|
||||
menu_state->next_item(pp.current_menu_ix);
|
||||
} else if (pp.current_menu_ix < pp.num_menus-1) {
|
||||
menu_state->next_item(pp.current_menu_ix+1);
|
||||
}
|
||||
return 1;
|
||||
case FL_Right:
|
||||
RIGHT:
|
||||
if (pp.in_menubar && (pp.current_menu_ix<=0 || (pp.current_menu_ix == pp.num_menus-1))) {
|
||||
menu_state->next_item(0);
|
||||
} else if (pp.current_menu_ix < pp.num_menus-1) {
|
||||
menu_state->next_item(pp.current_menu_ix+1);
|
||||
}
|
||||
return 1;
|
||||
case FL_Left:
|
||||
if (pp.in_menubar && pp.current_menu_ix<=1) {
|
||||
menu_state->prev_item(0);
|
||||
} else if (pp.current_menu_ix>0) {
|
||||
menu_state->set_current_item(pp.current_menu_ix-1, pp.menu_window[pp.current_menu_ix-1]->selected);
|
||||
}
|
||||
return 1;
|
||||
case FL_Enter:
|
||||
case FL_KP_Enter:
|
||||
case ' ':
|
||||
// if the current item is a submenu with no callback,
|
||||
// simulate FL_Right to enter the submenu
|
||||
if ( pp.current_item
|
||||
&& (!pp.in_menubar || pp.current_menu_ix > 0)
|
||||
&& pp.current_item->activevisible()
|
||||
&& pp.current_item->submenu()
|
||||
&& !pp.current_item->callback_)
|
||||
{
|
||||
goto RIGHT;
|
||||
}
|
||||
// Ignore keypresses over inactive items, mark KEYBOARD event as used.
|
||||
if (pp.current_item && !pp.current_item->selectable())
|
||||
return 1;
|
||||
// Mark the menu 'done' which will trigger the callback
|
||||
pp.state = State::DONE;
|
||||
return 1;
|
||||
case FL_Escape:
|
||||
menu_state->set_current_item(0, -1, 0);
|
||||
pp.state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
if (pp.handle_keyboard_event()) return 1;
|
||||
break;
|
||||
case FL_SHORTCUT:
|
||||
if (menu_state->handle_shortcut()) return 1;
|
||||
if (pp.handle_shortcut()) return 1;
|
||||
break;
|
||||
case FL_MOVE: {
|
||||
static int use_part1_extra = Fl::screen_driver()->need_menu_handle_part1_extra();
|
||||
if (use_part1_extra && pp.state == State::DONE) {
|
||||
return 1; // Fix for STR #2619
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case FL_MOVE:
|
||||
case FL_ENTER:
|
||||
case FL_PUSH:
|
||||
case FL_DRAG:
|
||||
{
|
||||
int mx = Fl::event_x_root();
|
||||
int my = Fl::event_y_root();
|
||||
item_index_t item = 0;
|
||||
menu_index_t mymenu = pp.num_menus-1;
|
||||
// Clicking or dragging outside menu cancels it...
|
||||
if ((!pp.in_menubar || mymenu) && !pp.is_inside(mx, my)) {
|
||||
menu_state->set_current_item(0, -1, 0);
|
||||
if (e==FL_PUSH)
|
||||
pp.state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
for (mymenu = pp.num_menus-1; ; mymenu--) {
|
||||
item = pp.menu_window[mymenu]->find_selected(mx, my);
|
||||
if (item >= 0)
|
||||
break;
|
||||
if (mymenu <= 0) {
|
||||
// buttons in menubars must be deselected if we move outside of them!
|
||||
if (pp.current_menu_ix==-1 && e==FL_PUSH) {
|
||||
pp.state = State::DONE;
|
||||
return 1;
|
||||
}
|
||||
if (pp.current_item && pp.current_menu_ix==0 && !pp.current_item->submenu()) {
|
||||
if (e==FL_PUSH) {
|
||||
pp.state = State::DONE;
|
||||
menu_state->set_current_item(0, -1, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// all others can stay selected
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
menu_state->set_current_item(mymenu, item);
|
||||
if (e == FL_PUSH) {
|
||||
if (pp.current_item && pp.current_item->submenu() // this is a menu title
|
||||
&& item != pp.menu_window[mymenu]->selected // and it is not already on
|
||||
&& !pp.current_item->callback_) // and it does not have a callback
|
||||
pp.state = State::MENU_PUSHED;
|
||||
else
|
||||
pp.state = State::PUSHED;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
case FL_RELEASE:
|
||||
// Mouse must either be held down/dragged some, or this must be
|
||||
// the second click (not the one that popped up the menu):
|
||||
if ( !Fl::event_is_click()
|
||||
|| pp.state == State::PUSHED
|
||||
|| (pp.in_menubar && pp.current_item && !pp.current_item->submenu()) // button
|
||||
) {
|
||||
#if 0 // makes the check/radio items leave the menu up
|
||||
const Fl_Menu_Item* m = pp.current_item;
|
||||
if (m && button && (m->flags & (FL_MENU_TOGGLE|FL_MENU_RADIO))) {
|
||||
((Fl_Menu_*)button)->picked(m);
|
||||
pp.p[pp.menu_number]->redraw();
|
||||
} else
|
||||
#endif
|
||||
// do nothing if they try to pick an inactive item, or a submenu with no callback
|
||||
if (!pp.current_item || (pp.current_item->selectable() &&
|
||||
(!pp.current_item->submenu() || pp.current_item->callback_ || (pp.in_menubar && pp.current_menu_ix <= 0))))
|
||||
pp.state = State::DONE;
|
||||
}
|
||||
return 1;
|
||||
if (pp.handle_mouse_events(e)) return 1;
|
||||
break;
|
||||
}
|
||||
return Fl_Window::handle(e);
|
||||
}
|
||||
@@ -913,65 +997,88 @@ bool Menu_Window::is_inside(int mx, int my) {
|
||||
void Menu_Window::draw_entry(const Fl_Menu_Item* m, int n, int eraseit) {
|
||||
if (!m) return; // this happens if -1 is selected item and redrawn
|
||||
|
||||
int BW = Fl::box_dx(box()); // left box inset
|
||||
int xx = BW; // left side of drawing area
|
||||
int W = w(); // box width
|
||||
int ww = W-2*BW-1; // width of drawing area
|
||||
int yy = BW+1+n*item_height+Fl::menu_linespacing()/2-2; // top of text, no spacing
|
||||
int hh = item_height - Fl::menu_linespacing(); // height of text without spacing
|
||||
Fl_Rect bbox {
|
||||
Fl::box_dx(box()),
|
||||
Fl::box_dy(box()) + 1 + n*item_height + Fl::menu_linespacing()/2 - 2,
|
||||
w() - Fl::box_dw(box()) - 1/*sic*/,
|
||||
item_height - Fl::menu_linespacing()
|
||||
};
|
||||
|
||||
// Clear the entire item rect including the spacing
|
||||
if (eraseit && n != selected) {
|
||||
fl_push_clip(xx+1, yy-(Fl::menu_linespacing()-2)/2, ww-2, hh+(Fl::menu_linespacing()-2));
|
||||
fl_push_clip(bbox.x()+1, bbox.y()-(Fl::menu_linespacing()-2)/2,
|
||||
bbox.w()-2, bbox.h()+(Fl::menu_linespacing()-2));
|
||||
draw_box(box(), 0, 0, w(), h(), button ? button->color() : color());
|
||||
fl_pop_clip();
|
||||
}
|
||||
|
||||
// Draw the checkbox, radio box, the menu icon, and the label
|
||||
m->draw(xx, yy, ww, hh, button, n==selected);
|
||||
m->draw(bbox.x(), bbox.y(), bbox.w(), bbox.h(), button, n==selected);
|
||||
|
||||
// Draw additional decorations on the right side of the label
|
||||
// the shortcuts and arrows assume fl_color() was left set by draw():
|
||||
if (m->submenu()) {
|
||||
// Draw the submenu arrow
|
||||
// calculate the bounding box of the submenu pointer (arrow)
|
||||
int sz = ((hh-2) & (-2)) + 1 ; // must be odd for better centering
|
||||
if (sz > 13) sz = 13; // limit arrow size
|
||||
int x1 = xx + ww - sz - 2; // left border
|
||||
int y1 = yy + (hh-sz)/2 + 1; // top border
|
||||
|
||||
// draw an arrow whose style depends on the active scheme
|
||||
fl_draw_arrow(Fl_Rect(x1, y1, sz, sz), FL_ARROW_SINGLE, FL_ORIENT_RIGHT, fl_color());
|
||||
|
||||
draw_submenu_arrow(bbox);
|
||||
} else if (m->shortcut_) {
|
||||
// Draw the shortcut modifiers and key texts
|
||||
Fl_Font f = m->labelsize_ || m->labelfont_ ? (Fl_Font)m->labelfont_ :
|
||||
button ? button->textfont() : FL_HELVETICA;
|
||||
fl_font(f, m->labelsize_ ? m->labelsize_ :
|
||||
button ? button->textsize() : FL_NORMAL_SIZE);
|
||||
const char *k, *s = fl_shortcut_label(m->shortcut_, &k);
|
||||
if (fl_utf_nb_char((const unsigned char*)k, (int) strlen(k))<=4) {
|
||||
// right-align the modifiers and left-align the key
|
||||
char *buf = (char*)malloc(k-s+1);
|
||||
memcpy(buf, s, k-s); buf[k-s] = 0;
|
||||
fl_draw(buf, xx, yy, ww-shortcut_width, hh, FL_ALIGN_RIGHT);
|
||||
fl_draw( k, xx+ww-shortcut_width, yy, shortcut_width, hh, FL_ALIGN_LEFT);
|
||||
free(buf);
|
||||
} else {
|
||||
// right-align to the menu
|
||||
fl_draw(s, xx, yy, ww-4, hh, FL_ALIGN_RIGHT);
|
||||
}
|
||||
draw_shortcut(bbox, m);
|
||||
}
|
||||
|
||||
// Draw the divider. It's part of the menu, but drawn in the spacing area.
|
||||
if (m->flags & FL_MENU_DIVIDER) {
|
||||
fl_color(FL_DARK3);
|
||||
fl_xyline(BW-1, yy+hh+(Fl::menu_linespacing()-2)/2, W-2*BW+2);
|
||||
fl_color(FL_LIGHT3);
|
||||
fl_xyline(BW-1, yy+hh+((Fl::menu_linespacing()-2)/2+1), W-2*BW+2);
|
||||
draw_divider(bbox);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the submenu arrow.
|
||||
\param[in] bbox menu item bounding box
|
||||
*/
|
||||
void Menu_Window::draw_submenu_arrow(const Fl_Rect& bbox) {
|
||||
// calculate the bounding box of the submenu pointer (arrow)
|
||||
int sz = ((bbox.h()-2) & (-2)) + 1 ; // must be odd for better centering
|
||||
if (sz > 13) sz = 13; // limit arrow size
|
||||
int x1 = bbox.x() + bbox.w() - sz - 2; // left border
|
||||
int y1 = bbox.y() + (bbox.h()-sz)/2 + 1; // top border
|
||||
|
||||
// draw an arrow whose style depends on the active scheme
|
||||
fl_draw_arrow(Fl_Rect(x1, y1, sz, sz), FL_ARROW_SINGLE, FL_ORIENT_RIGHT, fl_color());
|
||||
}
|
||||
|
||||
/* Draw the benu item shortcut text.
|
||||
\param[in] bbox menu item bounding box
|
||||
\param[in] m take the shortcut from this menu item
|
||||
*/
|
||||
// the shortcuts and arrows assume fl_color() was left set by draw():
|
||||
void Menu_Window::draw_shortcut(const Fl_Rect& bbox, const Fl_Menu_Item* m) {
|
||||
// Draw the shortcut modifiers and key texts
|
||||
Fl_Font f = m->labelsize_ || m->labelfont_ ? (Fl_Font)m->labelfont_ :
|
||||
button ? button->textfont() : FL_HELVETICA;
|
||||
fl_font(f, m->labelsize_ ? m->labelsize_ :
|
||||
button ? button->textsize() : FL_NORMAL_SIZE);
|
||||
const char *k, *s = fl_shortcut_label(m->shortcut_, &k);
|
||||
if (fl_utf_nb_char((const unsigned char*)k, (int) strlen(k))<=4) {
|
||||
// right-align the modifiers and left-align the key
|
||||
char *buf = (char*)malloc(k-s+1);
|
||||
memcpy(buf, s, k-s); buf[k-s] = 0;
|
||||
fl_draw(buf, bbox.x(), bbox.y(),
|
||||
bbox.w()-shortcut_width, bbox.h(), FL_ALIGN_RIGHT);
|
||||
fl_draw( k, bbox.x()+bbox.w()-shortcut_width, bbox.y(),
|
||||
shortcut_width, bbox.h(), FL_ALIGN_LEFT);
|
||||
free(buf);
|
||||
} else {
|
||||
// right-align to the menu
|
||||
fl_draw(s, bbox.x(), bbox.y(), bbox.w()-4, bbox.h(), FL_ALIGN_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the divider. It's part of the menu, but drawn in the spacing area.
|
||||
\param[in] bbox menu item bounding box
|
||||
*/
|
||||
void Menu_Window::draw_divider(const Fl_Rect& bbox) {
|
||||
int y_offset = (Fl::menu_linespacing()-2)/2;
|
||||
fl_color(FL_DARK3);
|
||||
fl_xyline(bbox.x()-1, bbox.b() + y_offset, bbox.r());
|
||||
fl_color(FL_LIGHT3);
|
||||
fl_xyline(bbox.x()-1, bbox.b() + y_offset+1, bbox.r());
|
||||
}
|
||||
|
||||
|
||||
/* Draw the menuwindow. If the damage flags are FL_DAMAGE_CHILD, only redraw
|
||||
the old selected and the newly selected items.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user