1 // ----------------------------------------------------------------------------
2 // icons.cxx
3 //
4 // Copyright (C) 2008
5 // Stelios Bounanos, M0GLD
6 //
7 // This file is part of fldigi.
8 //
9 // fldigi is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // fldigi is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // ----------------------------------------------------------------------------
22
23 #include <config.h>
24 #include "icons.h"
25
26 #include <FL/Fl.H>
27 #include <FL/Fl_Menu_Item.H>
28 #include <FL/Fl_Widget.H>
29 #include <FL/Fl_Group.H>
30
31 #if USE_IMAGE_LABELS
32 # include <map>
33 # include <cassert>
34 # include <cstring>
35
36 # include <FL/Fl_Multi_Label.H>
37 # include <FL/Fl_Image.H>
38 # include <FL/Fl_Pixmap.H>
39
40 #endif
41
42
43 using namespace std;
44
45 namespace icons {
46
47 #if USE_IMAGE_LABELS
48 typedef map<Fl_Multi_Label*, Fl_Image**> imap_t;
49 static imap_t* imap = 0;
50 #endif
51
52 #define FL_EMPTY_LABEL FL_FREE_LABELTYPE
draw_empty(const Fl_Label *,int,int,int,int,Fl_Align)53 static void draw_empty(const Fl_Label*, int, int, int, int, Fl_Align) { }
measure_empty(const Fl_Label *,int & w,int & h)54 static void measure_empty(const Fl_Label*, int& w, int& h) { w = h = 0; }
55
56 // The following functions create image+text menu item labels.
57 // You've had too much FLTK if you already know how to do that.
58
59
60 // Return a multi_label pointer, cast to a string, for `text' and
61 // `pixmap'. This goes into the label pointer of a widget or menu
62 // item. The text label is copied if we are using multi labels. You must
63 // call set_icon_label on the widget or menu item before its draw()
64 // function is called for the first time.
65 //
66 // A NULL pixmap means that the caller wants an empty, transparent, icon.
make_icon_label(const char * text,const char ** pixmap)67 const char* make_icon_label(const char* text, const char** pixmap)
68 {
69 #if USE_IMAGE_LABELS
70 static imap_t* imap_ = 0;
71 if (unlikely(!imap_)) {
72 imap = imap_ = new imap_t;
73 Fl::set_labeltype(FL_EMPTY_LABEL, draw_empty, measure_empty);
74 }
75
76 // Create a multi label and associate it with an Fl_Image* array
77 Fl_Multi_Label* mlabel = new Fl_Multi_Label;
78 Fl_Image** images = new Fl_Image*[2];
79 images[0] = new Fl_Pixmap(pixmap ? pixmap : clear_row_icon);
80 images[1] = 0; // we create this on demand
81 // set_icon_label_ will set mlabel->labela later
82 mlabel->typea = _FL_IMAGE_LABEL;
83
84 if (!text)
85 text = "";
86 size_t len = strlen(text);
87 char* s = new char[len + 2];
88 s[0] = ' ';
89 memcpy(s + 1, text, len + 1);
90 mlabel->labelb = s;
91 mlabel->typeb = FL_NORMAL_LABEL;
92
93 (*imap)[mlabel] = images;
94
95 return (const char*)mlabel;
96 #else
97 return text;
98 #endif
99 }
100
101 #if USE_IMAGE_LABELS
102 // Find the item's label, which should be something that was returned by
103 // make_icon_label, and set the active or inactive image.
104 template <typename T>
set_icon_label_(T * item)105 void set_icon_label_(T* item)
106 {
107 imap_t::iterator j = imap->find((Fl_Multi_Label*)(item->label()));
108 if (j == imap->end())
109 return;
110
111 Fl_Multi_Label* mlabel = j->first;
112 Fl_Image** images = j->second;
113 unsigned char i = !item->active();
114
115 if (!images[i]) { // create inactive version of other image
116 images[i] = images[!i]->copy();
117 images[i]->inactive();
118 }
119 if (mlabel->typea == _FL_IMAGE_LABEL)
120 mlabel->labela = (const char*)images[i];
121 else
122 mlabel->labelb = (const char*)images[i];
123 item->image(images[i]);
124 mlabel->label(item);
125 item->labeltype(_FL_MULTI_LABEL);
126 }
127 #endif
128
set_icon_label(Fl_Menu_Item * item)129 void set_icon_label(Fl_Menu_Item* item)
130 {
131 #if USE_IMAGE_LABELS
132 set_icon_label_(item);
133 #else
134 // this isn't needed but it simplifies fldigi's UI setup code
135 if (item->labeltype() == _FL_MULTI_LABEL)
136 item->labeltype(FL_NORMAL_LABEL);
137 #endif
138 }
139
set_icon_label(Fl_Widget * w)140 void set_icon_label(Fl_Widget* w)
141 {
142 #if USE_IMAGE_LABELS
143 set_icon_label_(w);
144 w->image(0);
145 #else
146 if (w->labeltype() == _FL_MULTI_LABEL)
147 w->labeltype(FL_NORMAL_LABEL);
148 #endif
149 }
150
toggle_icon_labels(void)151 void toggle_icon_labels(void)
152 {
153 #if USE_IMAGE_LABELS
154 for (imap_t::iterator i = imap->begin(); i != imap->end(); ++i) {
155 // swap sublabels
156 const char* l = i->first->labela;
157 i->first->labela = i->first->labelb;
158 i->first->labelb = l;
159 if (i->first->typea == _FL_IMAGE_LABEL) {
160 i->first->typea = FL_NORMAL_LABEL;
161 i->first->typeb = FL_EMPTY_LABEL;
162 i->first->labela++;
163 }
164 else {
165 i->first->typea = _FL_IMAGE_LABEL;
166 i->first->typeb = FL_NORMAL_LABEL;
167 i->first->labelb--;
168 }
169 }
170
171 #endif
172 }
173
174 template <typename T>
get_icon_label_text_(T * item)175 const char* get_icon_label_text_(T* item)
176 {
177 #if USE_IMAGE_LABELS
178 if (item->labeltype() == _FL_MULTI_LABEL) {
179 imap_t::iterator i = imap->find((Fl_Multi_Label*)(item->label()));
180 if (i == imap->end())
181 return 0;
182 if (i->first->typeb == FL_NORMAL_LABEL)
183 return i->first->labelb + 1;
184 else // disabled icons
185 return i->first->labela;
186 }
187 else
188 #endif
189 return item->label();
190 }
191
get_icon_label_text(Fl_Menu_Item * item)192 const char* get_icon_label_text(Fl_Menu_Item* item)
193 {
194 return get_icon_label_text_(item);
195 }
get_icon_label_text(Fl_Widget * w)196 const char* get_icon_label_text(Fl_Widget* w)
197 {
198 return get_icon_label_text_(w);
199 }
200
201 template <typename T>
free_icon_label_(T * item)202 void free_icon_label_(T* item)
203 {
204 #if USE_IMAGE_LABELS
205 if (item->labeltype() == FL_NORMAL_LABEL) {
206 delete [] item->label();
207 item->label(0);
208 return;
209 }
210
211 imap_t::iterator i = imap->find((Fl_Multi_Label*)item->label());
212 if (i == imap->end())
213 return;
214
215 item->label(0);
216
217 // delete the images
218 delete i->second[0];
219 delete i->second[1];
220 delete [] i->second;
221
222 // delete the multi label
223 delete [] ((i->first->typeb == FL_NORMAL_LABEL) ? i->first->labelb : i->first->labela-1);
224 delete i->first;
225
226 imap->erase(i);
227 #endif
228 }
229
free_icon_label(Fl_Menu_Item * item)230 void free_icon_label(Fl_Menu_Item* item) { free_icon_label_(item); }
free_icon_label(Fl_Widget * w)231 void free_icon_label(Fl_Widget* w) { free_icon_label_(w); }
232
233 template <typename T>
set_active_(T * t,bool v)234 void set_active_(T* t, bool v) {
235 if (v)
236 t->activate();
237 else
238 t->deactivate();
239 if (t->labeltype() == _FL_MULTI_LABEL)
240 set_icon_label(t);
241 }
242
set_active(Fl_Menu_Item * item,bool v)243 void set_active(Fl_Menu_Item* item, bool v) { set_active_(item, v); }
set_active(Fl_Widget * w,bool v)244 void set_active(Fl_Widget* w, bool v) { set_active_(w, v); }
245
246 static Fl_Image* msg_icon;
set_message_icon(const char ** pixmap)247 void set_message_icon(const char** pixmap)
248 {
249 if (msg_icon && msg_icon->data() == pixmap)
250 return;
251 delete msg_icon;
252
253 Fl_Widget* msg = fl_message_icon();
254 msg->label("");
255 msg->align(FL_ALIGN_TOP_LEFT | FL_ALIGN_INSIDE);
256 msg->color(msg->parent()->color());
257 msg->box(FL_NO_BOX);
258 msg->image(msg_icon = new Fl_Pixmap(pixmap));
259 }
260
261 } // icons
262