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