Add option to bind images to a widget (#589)

Adding image binding to FLUID as well
This commit is contained in:
Matthias Melcher 2022-12-10 23:22:24 +01:00 committed by GitHub
parent 8dcd121d44
commit a5adbd99ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 261 additions and 28 deletions

View File

@ -158,8 +158,9 @@ protected:
COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget
FULLSCREEN = 1<<18, ///< a fullscreen window (Fl_Window)
MAC_USE_ACCENTS_MENU = 1<<19, ///< On the Mac OS platform, pressing and holding a key on the keyboard opens an accented-character menu window (Fl_Input_, Fl_Text_Editor)
// (space for more flags)
NEEDS_KEYBOARD = 1<<20, ///< set this on touch screen devices if a widget needs a keyboard when it gets Focus. @see Fl_Screen_Driver::request_keyboard()
IMAGE_BOUND = 1<<21, ///< binding the image to the widget will transfer ownership, so that the widget will delete the image when it is no longer needed
DEIMAGE_BOUND = 1<<22, ///< bind the inactive image to the widget, so the widget deletes the image when it no longer needed
// a tiny bit more space for new flags...
USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions
USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions
@ -518,45 +519,109 @@ public:
\return the current image
*/
Fl_Image* image() {return label_.image;}
/** Gets the image that is used as part of the widget label when in the active state.
\return the current image
*/
const Fl_Image* image() const {return label_.image;}
/** Sets the image to use as part of the widget label when in the active state.
\param[in] img the new image for the label
\note The caller is responsible for making sure \p img is not deleted while it's used by the widget,
The caller is responsible for making sure \p img is not deleted while it's used by the widget,
and, if appropriate, for deleting it after the widget's deletion.
Calling image() with a new image will delete the old image if it
was bound, and set the new image without binding it. If old and new are
the same, the image will not be deleted, but it will be unbound.
Calling image() with NULL will delete the old image if
it was bound and not set a new image.
\param[in] img the new image for the label
\see bind_image(Fl_Image* img)
*/
void image(Fl_Image* img) {label_.image=img;}
void image(Fl_Image* img);
/** Sets the image to use as part of the widget label when in the active state.
\param[in] img the new image for the label
\param[in] img the new image for the label
\see void image(Fl_Image* img)
*/
void image(Fl_Image& img) {label_.image=&img;}
void image(Fl_Image& img);
/** Sets the image to use as part of the widget label when in the active state.
The image will be bound to the widget. When the widget is deleted, the
image will be deleted as well.
Calling bind_image() with a new image will delete the old image if it
was bound, and then set the new image, and bind that. If old and new image
are the same, nothing happens.
Calling bind_image() with NULL will delete the old image if
it was bound and not set a new image.
\param[in] img the new image for the label
\see void image(Fl_Image* img)
*/
void bind_image(Fl_Image* img);
/** Bind the image to the widget, so the widget will delete the image when it is no longer needed.
\param f 1: mark the image as bound, 0: mark the image as managed by the user
\see image_bound(), bind_deimage()
*/
void bind_image(int f) { if (f) set_flag(IMAGE_BOUND); else clear_flag(IMAGE_BOUND); }
/** Returns whether the image is managed by the widget.
\retval 0 if the image is not bound to the widget
\retval 1 if the image will be deleted when the widget is deleted
\see deimage_bound(), bind_image()
*/
int image_bound() const {return ((flags_ & IMAGE_BOUND) ? 1 : 0);}
/** Gets the image that is used as part of the widget label when in the inactive state.
\return the current image for the deactivated widget
*/
Fl_Image* deimage() {return label_.deimage;}
/** Gets the image that is used as part of the widget label when in the inactive state.
\return the current image for the deactivated widget
*/
const Fl_Image* deimage() const {return label_.deimage;}
/** Sets the image to use as part of the widget label when in the inactive state.
\param[in] img the new image for the deactivated widget
\note The caller is responsible for making sure \p img is not deleted while it's used by the widget,
\param[in] img the new image for the deactivated widget
\note The caller is responsible for making sure \p img is not deleted while it's used by the widget,
and, if appropriate, for deleting it after the widget's deletion.
\see void bind_deimage(Fl_Image* img)
*/
void deimage(Fl_Image* img) {label_.deimage=img;}
void deimage(Fl_Image* img);
/** Sets the image to use as part of the widget label when in the inactive state.
\param[in] img the new image for the deactivated widget
\param[in] img the new image for the deactivated widget
\see void deimage(Fl_Image* img)
*/
void deimage(Fl_Image& img) {label_.deimage=&img;}
void deimage(Fl_Image& img);
/** Sets the image to use as part of the widget label when in the inactive state.
\param[in] img the new image for the deactivated widget
\note The image will be bound to the widget. When the widget is deleted, the
image will be deleted as well.
\see void deimage(Fl_Image* img)
*/
void bind_deimage(Fl_Image* img);
/** Returns whether the inactive image is managed by the widget.
\retval 0 if the image is not bound to the widget
\retval 1 if the image will be deleted when the widget is deleted
\see image_bound(), bind_deimage()
*/
int deimage_bound() const {return ((flags_ & DEIMAGE_BOUND) ? 1 : 0);}
/** Bind the inactive image to the widget, so the widget will delete the image when it is no longer needed.
\param f 1: mark the image as bound, 0: mark the image as managed by the user
\see deimage_bound(), bind_image()
*/
void bind_deimage(int f) { if (f) set_flag(DEIMAGE_BOUND); else clear_flag(DEIMAGE_BOUND); }
/** Gets the current tooltip text.
\return a pointer to the tooltip text or NULL

View File

@ -488,7 +488,7 @@ void Fl_Menu_Item_Type::write_code1() {
write_c("%sml->typeb = FL_NORMAL_LABEL;\n", indent());
write_c("%sml->label(o);\n", indent());
} else {
image->write_code("o");
image->write_code(0, "o");
}
}
if (P.i18n_type && label() && label()[0]) {

View File

@ -210,6 +210,8 @@ Fl_Widget_Type::Fl_Widget_Type() {
xclass = 0;
o = 0;
public_ = 1;
bind_image_ = 0;
bind_deimage_ = 0;
}
Fl_Widget_Type::~Fl_Widget_Type() {
@ -475,6 +477,26 @@ void image_browse_cb(Fl_Button* b, void *v) {
}
}
void bind_image_cb(Fl_Button* b, void *v) {
if (v == LOAD) {
if (current_widget->is_widget() && !current_widget->is_window()) {
b->activate();
b->value(current_widget->bind_image_);
} else {
b->deactivate();
}
} else {
int mod = 0;
for (Fl_Type *o = Fl_Type::first; o; o = o->next) {
if (o->selected && o->is_widget()) {
((Fl_Widget_Type*)o)->bind_image_ = b->value();
mod = 1;
}
}
if (mod) set_modflag(1);
}
}
static Fl_Input *inactive_input;
void inactive_cb(Fl_Input* i, void *v) {
@ -517,6 +539,26 @@ void inactive_browse_cb(Fl_Button* b, void *v) {
}
}
void bind_deimage_cb(Fl_Button* b, void *v) {
if (v == LOAD) {
if (current_widget->is_widget() && !current_widget->is_window()) {
b->activate();
b->value(current_widget->bind_deimage_);
} else {
b->deactivate();
}
} else {
int mod = 0;
for (Fl_Type *o = Fl_Type::first; o; o = o->next) {
if (o->selected && o->is_widget()) {
((Fl_Widget_Type*)o)->bind_deimage_ = b->value();
mod = 1;
}
}
if (mod) set_modflag(1);
}
}
void tooltip_cb(Fl_Input* i, void *v) {
if (v == LOAD) {
if (current_widget->is_widget()) {
@ -2917,8 +2959,8 @@ void Fl_Widget_Type::write_widget_code() {
write_color("color", o->color());
if (o->selection_color() != tplate->selection_color() || subclass())
write_color("selection_color", o->selection_color());
if (image) image->write_code(var);
if (inactive) inactive->write_code(var, 1);
if (image) image->write_code(bind_image_, var);
if (inactive) inactive->write_code(bind_deimage_, var, 1);
if (o->labeltype() != tplate->labeltype() || subclass())
write_c("%s%s->labeltype(FL_%s);\n", indent(), var,
item_name(labeltypemenu, o->labeltype()));
@ -3044,10 +3086,12 @@ void Fl_Widget_Type::write_properties() {
write_string("image");
write_word(image_name());
}
if (bind_image_) write_string("bind_image 1");
if (inactive_name() && *inactive_name()) {
write_string("deimage");
write_word(inactive_name());
}
if (bind_deimage_) write_string("bind_deimage 1");
write_string("xywh {%d %d %d %d}", o->x(), o->y(), o->w(), o->h());
Fl_Widget* tplate = ((Fl_Widget_Type*)factory)->o;
if (is_spinner() && ((Fl_Spinner*)o)->type() != ((Fl_Spinner*)tplate)->type()) {
@ -3168,8 +3212,12 @@ void Fl_Widget_Type::read_property(const char *c) {
tooltip(read_word());
} else if (!strcmp(c,"image")) {
image_name(read_word());
} else if (!strcmp(c,"bind_image")) {
bind_image_ = (int)atol(read_word());
} else if (!strcmp(c,"deimage")) {
inactive_name(read_word());
} else if (!strcmp(c,"bind_deimage")) {
bind_deimage_ = (int)atol(read_word());
} else if (!strcmp(c,"type")) {
if (is_spinner())
((Fl_Spinner*)o)->type(item_number(subtypes(), read_word()));

View File

@ -66,6 +66,8 @@ public:
const char *xclass; // junk string, used for shortcut
Fl_Widget *o;
int public_;
int bind_image_;
int bind_deimage_;
Fluid_Image *image;
void setimage(Fluid_Image *);

View File

@ -200,10 +200,10 @@ void Fluid_Image::write_initializer(const char *type_name, const char *format, .
va_end(ap);
}
void Fluid_Image::write_code(const char *var, int inactive) {
void Fluid_Image::write_code(int bind, const char *var, int inactive) {
/* Outputs code that attaches an image to an Fl_Widget or Fl_Menu_Item.
This code calls a function output before by Fluid_Image::write_initializer() */
if (img) write_c("%s%s->%s( %s() );\n", indent(), var, inactive ? "deimage" : "image", function_name_);
if (img) write_c("%s%s->%s%s( %s() );\n", indent(), var, bind ? "bind_" : "", inactive ? "deimage" : "image", function_name_);
}
void Fluid_Image::write_inline(int inactive) {

View File

@ -40,7 +40,7 @@ public:
void deimage(Fl_Widget *); // set the deimage of this widget
void write_static();
void write_initializer(const char *type_name, const char *format, ...);
void write_code(const char *var, int inactive = 0);
void write_code(int bind, const char *var, int inactive = 0);
void write_inline(int inactive = 0);
void write_file_error(const char *fmt);
const char *name() const {return name_;}

View File

@ -380,7 +380,9 @@ Type "Fl_Widget" <word> : C++ variable name
"xywh" <word> : "{%d %d %d %d}" x, y, w, h
"tooltip" <word> : tooltip text
"image" <word> : image name
"bind_image" <word> : integer (1.4 and up)
"deimage" <word> : deactivated image name
"bind_deimage" <word> : integer (1.4 and up)
"type" <word> : integer
"box" <word> : text or integer (see FLTK boxtypes)
"down_box" <word> : (is_button() or Fl_Input_choice" or is_menu_button())

View File

@ -18,6 +18,7 @@
#include <FL/Fl_Pixmap.H>
#include "pixmaps/bind.xpm"
#include "pixmaps/lock.xpm"
#include "pixmaps/protected.xpm"
#include "pixmaps/invisible.xpm"
@ -79,6 +80,7 @@
#include "pixmaps/flRadioMenuitem.xpm"
#include "pixmaps/flFlex.xpm"
Fl_Pixmap *bind_pixmap;
Fl_Pixmap *lock_pixmap;
Fl_Pixmap *protected_pixmap;
Fl_Pixmap *invisible_pixmap;
@ -144,6 +146,7 @@ Fl_Pixmap *pixmap[57];
void loadPixmaps()
{
bind_pixmap = new Fl_Pixmap(bind_xpm); bind_pixmap->scale(16, 16);
lock_pixmap = new Fl_Pixmap(lock_xpm); lock_pixmap->scale(16, 16);
protected_pixmap = new Fl_Pixmap(protected_xpm); protected_pixmap->scale(16, 16);
invisible_pixmap = new Fl_Pixmap(invisible_xpm); invisible_pixmap->scale(16, 16);

View File

@ -19,6 +19,7 @@
class Fl_Pixmap;
extern Fl_Pixmap *bind_pixmap;
extern Fl_Pixmap *lock_pixmap;
extern Fl_Pixmap *protected_pixmap;
extern Fl_Pixmap *invisible_pixmap;

45
fluid/pixmaps/bind.xpm Normal file
View File

@ -0,0 +1,45 @@
/* cPM */
static const char * const bind_xpm[] = {
/* width height ncolors chars_per_picel */
"32 32 6 1",
/* colors */
"- c #aaaaaa",
"= c #666666",
"c c none",
"d c #cccccc",
". c #000000",
", c #222222",
/* pixels */
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccc,,,,,,,,,,,,,,cccccc",
"cccccccccc,,................cccc",
"ccccccccc,...................ccc",
"ccccccccc======..............ccc",
"cccccccc------cccccccccc......cc",
"cccccccc-----cccccccccccc.....cc",
"cccccc,,,,,,,,,,,,,,cccccc....cc",
"cccc,,................cccc....cc",
"ccc,...................ccc....cc",
"cc,...............=====ccc....cc",
"cc......-----cccccc-----c,....cc",
"cc.....c-----cccccc-----,.....cc",
"cc....ccc=====,,,,,,,,,,.....ccc",
"cc....ccc....................ccc",
"cc....cccc..................cccc",
"cc....cccccc..............cccccc",
"cc.....cccccccccccc-----cccccccc",
"cc......cccccccccc------cccccccc",
"ccc.....,,,,,,,,=======ccccccccc",
"ccc....................ccccccccc",
"cccc..................cccccccccc",
"cccccc..............cccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccc"
};

View File

@ -165,7 +165,7 @@ Fl_Double_Window* make_widget_panel() {
o->labelsize(11);
o->callback((Fl_Callback*)propagate_load);
o->align(Fl_Align(FL_ALIGN_LEFT));
{ Fl_Input* o = new Fl_Input(95, 65, 240, 20);
{ Fl_Input* o = new Fl_Input(95, 65, 220, 20);
o->tooltip("The active image for the widget.");
o->labelfont(1);
o->labelsize(11);
@ -173,11 +173,17 @@ Fl_Double_Window* make_widget_panel() {
o->callback((Fl_Callback*)image_cb);
Fl_Group::current()->resizable(o);
} // Fl_Input* o
{ Fl_Button* o = new Fl_Button(334, 65, 70, 20, "Browse...");
{ Fl_Button* o = new Fl_Button(314, 65, 70, 20, "Browse...");
o->tooltip("Click to choose the active image.");
o->labelsize(11);
o->callback((Fl_Callback*)image_browse_cb);
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(384, 65, 20, 20);
o->tooltip("bind the image to the widget, so it will be deleted automatically");
o->type(1);
o->callback((Fl_Callback*)bind_image_cb);
o->image(bind_pixmap);
} // Fl_Button* o
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(95, 90, 309, 20, "Inactive:");
@ -185,7 +191,7 @@ Fl_Double_Window* make_widget_panel() {
o->labelsize(11);
o->callback((Fl_Callback*)propagate_load);
o->align(Fl_Align(FL_ALIGN_LEFT));
{ Fl_Input* o = new Fl_Input(95, 90, 240, 20);
{ Fl_Input* o = new Fl_Input(95, 90, 220, 20);
o->tooltip("The inactive image for the widget.");
o->labelfont(1);
o->labelsize(11);
@ -193,11 +199,17 @@ Fl_Double_Window* make_widget_panel() {
o->callback((Fl_Callback*)inactive_cb);
Fl_Group::current()->resizable(o);
} // Fl_Input* o
{ Fl_Button* o = new Fl_Button(334, 90, 70, 20, "Browse...");
{ Fl_Button* o = new Fl_Button(314, 90, 70, 20, "Browse...");
o->tooltip("Click to choose the inactive image.");
o->labelsize(11);
o->callback((Fl_Callback*)inactive_browse_cb);
} // Fl_Button* o
{ Fl_Button* o = new Fl_Button(384, 90, 20, 20);
o->tooltip("bind the image to the widget, so it will be deleted automatically");
o->type(1);
o->callback((Fl_Callback*)bind_deimage_cb);
o->image(bind_pixmap);
} // Fl_Button* o
o->end();
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(95, 115, 310, 20, "Alignment:");

View File

@ -49,7 +49,7 @@ Function {make_widget_panel()} {
xywh {95 40 309 20} labelfont 1 labelsize 11 align 4
} {
Fl_Input {} {
callback label_cb selected
callback label_cb
tooltip {The label text for the widget.
Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 textsize 11 resizable
}
@ -62,32 +62,44 @@ Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 t
}
Fl_Group {} {
label {Image:}
callback propagate_load
callback propagate_load open
xywh {95 65 309 20} labelfont 1 labelsize 11 align 4
} {
Fl_Input {} {
callback image_cb
tooltip {The active image for the widget.} xywh {95 65 240 20} labelfont 1 labelsize 11 textsize 11 resizable
tooltip {The active image for the widget.} xywh {95 65 220 20} labelfont 1 labelsize 11 textsize 11 resizable
}
Fl_Button {} {
label {Browse...}
callback image_browse_cb
tooltip {Click to choose the active image.} xywh {334 65 70 20} labelsize 11
tooltip {Click to choose the active image.} xywh {314 65 70 20} labelsize 11
}
Fl_Button {} {
callback bind_image_cb selected
tooltip {bind the image to the widget, so it will be deleted automatically} xywh {384 65 20 20} type Toggle
code0 {o->image(bind_pixmap);}
code3 {\#include "pixmaps.h"}
}
}
Fl_Group {} {
label {Inactive:}
callback propagate_load
callback propagate_load open
xywh {95 90 309 20} labelfont 1 labelsize 11 align 4
} {
Fl_Input {} {
callback inactive_cb
tooltip {The inactive image for the widget.} xywh {95 90 240 20} labelfont 1 labelsize 11 textsize 11 resizable
tooltip {The inactive image for the widget.} xywh {95 90 220 20} labelfont 1 labelsize 11 textsize 11 resizable
}
Fl_Button {} {
label {Browse...}
callback inactive_browse_cb
tooltip {Click to choose the inactive image.} xywh {334 90 70 20} labelsize 11
tooltip {Click to choose the inactive image.} xywh {314 90 70 20} labelsize 11
}
Fl_Button {} {
callback bind_deimage_cb
tooltip {bind the image to the widget, so it will be deleted automatically} xywh {384 90 20 20} type Toggle
code0 {o->image(bind_pixmap);}
code3 {\#include "pixmaps.h"}
}
}
Fl_Group {} {

View File

@ -32,8 +32,11 @@ extern void labeltype_cb(Fl_Choice*, void*);
extern void image_cb(Fl_Input*, void*);
#include <FL/Fl_Button.H>
extern void image_browse_cb(Fl_Button*, void*);
#include "pixmaps.h"
extern void bind_image_cb(Fl_Button*, void*);
extern void inactive_cb(Fl_Input*, void*);
extern void inactive_browse_cb(Fl_Button*, void*);
extern void bind_deimage_cb(Fl_Button*, void*);
extern void align_cb(Fl_Button*, void*);
extern void align_text_image_cb(Fl_Choice*, void*);
extern void align_position_cb(Fl_Choice*, void*);

View File

@ -165,6 +165,8 @@ Fl_Widget::~Fl_Widget() {
Fl::clear_widget_pointer(this);
if (flags() & COPIED_LABEL) free((void *)(label_.value));
if (flags() & COPIED_TOOLTIP) free((void *)(tooltip_));
image(NULL);
deimage(NULL);
// remove from parent group
if (parent_) parent_->remove(this);
#ifdef DEBUG_DELETE
@ -323,6 +325,44 @@ void Fl_Widget::copy_label(const char *a) {
}
}
void Fl_Widget::image(Fl_Image* img) {
if (image_bound()) {
if (label_.image && (label_.image != img)) {
label_.image->release();
}
bind_image(0);
}
label_.image = img;
}
void Fl_Widget::image(Fl_Image& img) {
image(&img);
}
void Fl_Widget::bind_image(Fl_Image* img) {
image(img);
bind_image( (img != NULL) );
}
void Fl_Widget::deimage(Fl_Image* img) {
if (deimage_bound()) {
if (label_.deimage && (label_.deimage != img)) {
label_.deimage->release();
}
bind_deimage(0);
}
label_.deimage = img;
}
void Fl_Widget::deimage(Fl_Image& img) {
deimage(&img);
}
void Fl_Widget::bind_deimage(Fl_Image* img) {
deimage(img);
bind_deimage( (img != NULL) );
}
/** Calls the widget callback function with arbitrary arguments.
All overloads of do_callback() call this method.