mirror of https://github.com/fltk/fltk
217 lines
6.9 KiB
C++
217 lines
6.9 KiB
C++
//
|
|
// How to use Fl_Multi_Label to make menu items with images and labels.
|
|
//
|
|
// Copyright 2017 Greg Ercolano.
|
|
// Copyright 1998-2023 by Bill Spitzak and others.
|
|
//
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
// file is missing or damaged, see the license at:
|
|
//
|
|
// https://www.fltk.org/COPYING.php
|
|
//
|
|
// Please see the following page on how to report bugs and issues:
|
|
//
|
|
// https://www.fltk.org/bugs.php
|
|
//
|
|
|
|
#include <FL/Fl.H>
|
|
#include <FL/Fl_Double_Window.H>
|
|
#include <FL/Fl_Menu_Bar.H>
|
|
#include <FL/Fl_Menu_Button.H>
|
|
#include <FL/Fl_Choice.H>
|
|
#include <FL/Fl_Multi_Label.H>
|
|
#include <FL/Fl_Button.H>
|
|
#include <FL/Fl_Box.H>
|
|
#include <FL/Fl_Pixmap.H>
|
|
#include <FL/fl_message.H>
|
|
|
|
#include <stdlib.h> // free()
|
|
|
|
// Document icon
|
|
static const char *L_document_xpm[] = {
|
|
"13 11 3 1",
|
|
" c None",
|
|
"x c #d8d8f8",
|
|
"@ c #202060",
|
|
" @@@@@@@@@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @xxxxxxx@ ",
|
|
" @@@@@@@@@ "};
|
|
static Fl_Pixmap L_document_pixmap(L_document_xpm);
|
|
|
|
// Folder icon
|
|
static const char *L_folder_xpm[] = {
|
|
"13 11 3 1",
|
|
" c None",
|
|
"x c #d8d833",
|
|
"@ c #808011",
|
|
" ",
|
|
" @@@@ ",
|
|
" @xxxx@ ",
|
|
"@@@@@xxxx@@ ",
|
|
"@xxxxxxxxx@ ",
|
|
"@xxxxxxxxx@ ",
|
|
"@xxxxxxxxx@ ",
|
|
"@xxxxxxxxx@ ",
|
|
"@xxxxxxxxx@ ",
|
|
"@xxxxxxxxx@ ",
|
|
"@@@@@@@@@@@ "};
|
|
static Fl_Pixmap L_folder_pixmap(L_folder_xpm);
|
|
|
|
// Red "X"
|
|
static const char *L_redx_xpm[] = {
|
|
"13 11 5 1",
|
|
" c None",
|
|
"+ c #222222",
|
|
"x c #555555",
|
|
"- c #882222",
|
|
"@ c #ffffff",
|
|
" x+++x ",
|
|
" ++---++ ",
|
|
" ++-----++ ",
|
|
"++-@@-@@-++ ",
|
|
"++--@@@--++ ",
|
|
"++---@---++ ",
|
|
"++--@@@--++ ",
|
|
"++-@@-@@-++ ",
|
|
" ++-----++ ",
|
|
" ++---++ ",
|
|
" x+++x "};
|
|
static Fl_Pixmap L_redx_pixmap(L_redx_xpm);
|
|
|
|
// Handle the different menu items..
|
|
void Menu_CB(Fl_Widget *w, void* data) {
|
|
const char *itemname = (const char*)data; // "New", "Open", etc
|
|
if ( strcmp(itemname, "Quit") == 0 ) { // handle Quit
|
|
w->window()->hide();
|
|
} else { // just show a message for other items
|
|
fl_message("'%s' would happen here", itemname);
|
|
}
|
|
}
|
|
|
|
// Add an image in front of item's text
|
|
int AddItemToMenu(Fl_Menu_ *menu, // menu to add item to
|
|
const char *labeltext, // label text
|
|
int shortcut, // shortcut (e.g. FL_COMMAND+'a')
|
|
Fl_Callback *cb, // callback to invoke
|
|
void *userdata, // userdata for callback
|
|
Fl_Pixmap* pixmap, // image (if any) to add to item
|
|
int flags=0) { // menu flags (e.g. FL_MENU_DIVIDER..)
|
|
// Add a new menu item
|
|
int i = menu->add(labeltext, shortcut, cb, userdata, flags);
|
|
|
|
if ( !pixmap ) return i;
|
|
Fl_Menu_Item *item = (Fl_Menu_Item*)&(menu->menu()[i]);
|
|
|
|
// Create a multi label, assign it an image + text
|
|
Fl_Multi_Label *ml = new Fl_Multi_Label;
|
|
|
|
// Left side of label is image
|
|
ml->typea = FL_IMAGE_LABEL;
|
|
ml->labela = (const char*)pixmap;
|
|
|
|
// Right side of label is text
|
|
ml->typeb = FL_NORMAL_LABEL;
|
|
ml->labelb = item->label(); // transfers "ownership" to ml
|
|
|
|
// Assign multilabel to item.
|
|
// There are three documented ways to achieve this. All of them are still
|
|
// supported but two of them are deprecated (see docs and comments below).
|
|
// The recommended way is to use Fl_Menu_Item::multi_label(Fl_Multi_Label *)
|
|
// which was added in FLTK 1.4.0 and sets the correct labeltype().
|
|
// All of these statements overwrite the old label (pointer) whose
|
|
// ownership has been "transferred" to the Fl_Multi_Label (correct).
|
|
// The old label is not released (as documented).
|
|
|
|
// ml->label(item); // deprecated (1.3.x)
|
|
// item->label(FL_MULTI_LABEL, (const char *)ml); // deprecated (1.3.x)
|
|
item->multi_label(ml); // new since 1.4.0
|
|
|
|
return i;
|
|
}
|
|
|
|
// Create Menu Items
|
|
// This same technique works for Fl_Menu_ derived widgets,
|
|
// e.g. Fl_Menu_Bar, Fl_Menu_Button, Fl_Choice..
|
|
//
|
|
void CreateMenuItems(Fl_Menu_* menu) {
|
|
|
|
// Add items with LABELS AND IMAGES using Fl_Multi_Label..
|
|
AddItemToMenu(menu, "File/New", FL_COMMAND+'n', Menu_CB, (void*)"New", &L_document_pixmap);
|
|
AddItemToMenu(menu, "File/Open", FL_COMMAND+'o', Menu_CB, (void*)"Open", &L_folder_pixmap, FL_MENU_DIVIDER);
|
|
AddItemToMenu(menu, "File/Quit", FL_COMMAND+'q', Menu_CB, (void*)"Quit", &L_redx_pixmap);
|
|
|
|
// Create menu bar items with JUST LABELS
|
|
menu->add("Edit/Copy", FL_COMMAND+'c', Menu_CB, (void*)"Copy");
|
|
menu->add("Edit/Paste", FL_COMMAND+'v', Menu_CB, (void*)"Paste");
|
|
|
|
// Create menu bar items with JUST IMAGES (no labels)
|
|
// This shows why you need Fl_Multi_Label; the item->label()
|
|
// gets clobbered by the item->image() setting.
|
|
//
|
|
// In the following lines 'menu->add(...)' assigns a duplicated label
|
|
// string which must be released prior to assigning an image to the label
|
|
// with 'item->image()'.
|
|
// This is "not nice" but it prevents memory leaks (see GitHub Issue #875).
|
|
|
|
int i;
|
|
Fl_Menu_Item *item;
|
|
|
|
i = menu->add("Images/One", 0, Menu_CB, (void*)"One");
|
|
item = (Fl_Menu_Item*)&(menu->menu()[i]);
|
|
free((void*)item->label());
|
|
item->image(L_document_pixmap);
|
|
|
|
i = menu->add("Images/Two", 0, Menu_CB, (void*)"Two");
|
|
item = (Fl_Menu_Item*)&(menu->menu()[i]);
|
|
free((void*)item->label());
|
|
item->image(L_folder_pixmap);
|
|
|
|
i = menu->add("Images/Three", 0, Menu_CB, (void*)"Three");
|
|
item = (Fl_Menu_Item*)&(menu->menu()[i]);
|
|
free((void*)item->label());
|
|
item->image(L_redx_pixmap);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
Fl_Double_Window *win = new Fl_Double_Window(400, 400, "Menu items with images");
|
|
win->tooltip("Right click on window background\nfor popup menu");
|
|
|
|
// Help message
|
|
Fl_Box *box = new Fl_Box(100,100,200,200);
|
|
box->label(win->tooltip()); // no need to copy_label() because it's static
|
|
box->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
|
|
|
|
// Menu bar
|
|
Fl_Menu_Bar *menubar = new Fl_Menu_Bar(0,0,win->w(), 25);
|
|
CreateMenuItems(menubar);
|
|
|
|
// Right click context menu
|
|
Fl_Menu_Button *menubutt = new Fl_Menu_Button(0,25,win->w(), win->h()-25);
|
|
CreateMenuItems(menubutt);
|
|
menubutt->type(Fl_Menu_Button::POPUP3);
|
|
|
|
// Chooser menu
|
|
Fl_Choice *choice = new Fl_Choice(140,50,200,25,"Choice");
|
|
CreateMenuItems(choice);
|
|
choice->value(1);
|
|
|
|
// TODO: Show complex labels with Fl_Multi_Label. From docs:
|
|
//
|
|
// "More complex labels can be constructed by setting labelb as another
|
|
// Fl_Multi_Label and thus chaining up a series of label elements."
|
|
|
|
win->end();
|
|
win->resizable(win);
|
|
win->show(argc, argv);
|
|
return Fl::run();
|
|
}
|