1 /* Defines Box::ucompose(fmt, arg...) for easy, i18n-friendly
2 * composition of labels and images with Gtkmm >= 1.3.* (see www.gtkmm.org).
3 * Uses Glib::ustring instead of std::string which doesn't work with
4 * Gtkmm due to character encoding troubles with stringstreams.
8 * Copyright (c) 2002, 03, 04 Ole Laursen <olau@hardworking.dk>.
9 * modified from String::ucompose by Ole.
10 * Changed by Ben Asselstine to create HBoxes instead.
11 * Copyright (C) 2009 Ben Asselstine
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public License
15 * as published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this file; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 // Basic usage is like
32 // Box::ucompose("This is a %1x%2 matrix.", rows, cols);
35 #ifndef BOX_UCOMPOSE_H
36 #define BOX_UCOMPOSE_H
38 #include <glibmm/ustring.h>
39 #include <glibmm/convert.h>
44 #include <map> // for multimap
48 // the actual composition class - using String::ucompose is cleaner, so we
53 // initialize and prepare format string on the form "text %1 text %2 etc."
54 explicit Composition(std::string fmt);
56 // supply an replacement argument starting from %1
58 Composition &arg(const T &obj);
60 // compose and return string
61 Gtk::HBox *box() const;
64 //Glib::ustring str() const;
65 std::wostringstream os;
68 // we store the output as a list - when the output string is requested, the
69 // list is concatenated to a string; this way we can keep iterators into
70 // the list instead of into a string where they're possibly invalidated
71 // when inserting a specification string
72 typedef std::list<std::string> output_list;
75 // the initial parse of the format string fills in the specification map
76 // with positions for each of the various %?s
77 typedef std::multimap<int, output_list::iterator> specification_map;
78 specification_map specs;
81 std::string stringify(T obj);
84 // helper for converting spec string numbers
85 inline int char_to_int(char c)
98 default: return -1000;
102 inline bool is_number(int n)
122 template <typename T>
123 inline std::string Composition::stringify(T obj)
127 std::wstring str = os.str();
129 return Glib::convert(std::string(reinterpret_cast<const char *>(str.data()),
130 str.size() * sizeof(wchar_t)),
134 // specialisations for the common string types
137 Composition::stringify<std::string>(std::string obj)
144 Composition::stringify<Glib::ustring>(Glib::ustring obj)
151 Composition::stringify<const char *>(const char *obj)
158 Composition::stringify<Glib::RefPtr<Gdk::Pixbuf> >(Glib::RefPtr<Gdk::Pixbuf> obj)
161 snprintf(buf, sizeof(buf), "Gdk::Pixbuf %p", obj->gobj());
165 // implementation of class Composition
166 template <typename T>
167 inline Composition &Composition::arg(const T &obj)
169 Glib::ustring rep = stringify(obj);
171 if (!rep.empty()) { // manipulators don't produce output
172 for (specification_map::const_iterator i = specs.lower_bound(arg_no),
173 end = specs.upper_bound(arg_no); i != end; ++i) {
174 output_list::iterator pos = i->second;
177 output.insert(pos, rep);
180 os.str(std::wstring());
188 inline Composition::Composition(std::string fmt)
192 //os.imbue(std::locale("")); // use the user's locale for the stream
194 std::string::size_type b = 0, i = 0;
196 // fill in output with the strings between the %1 %2 %3 etc. and
197 // fill in specs with the positions
198 while (i < fmt.length()) {
199 if (fmt[i] == '%' && i + 1 < fmt.length()) {
200 if (fmt[i + 1] == '%') { // catch %%
201 fmt.replace(i, 2, "%");
204 else if (is_number(fmt[i + 1])) { // aha! a spec!
206 output.push_back(fmt.substr(b, i - b));
208 int n = 1; // number of digits
212 spec_no += char_to_int(fmt[i + n]);
215 } while (i + n < fmt.length() && is_number(fmt[i + n]));
218 output_list::iterator pos = output.end();
219 --pos; // safe since we have just inserted a string
221 specs.insert(specification_map::value_type(spec_no, pos));
223 // jump over spec string
234 if (i - b > 0) // add the rest of the string
235 output.push_back(fmt.substr(b, i - b));
238 //inline Glib::ustring Composition::str() const
243 //for (output_list::const_iterator i = output.begin(), end = output.end();
249 inline Gtk::HBox* Composition::box() const
251 Gtk::HBox *hbox = new Gtk::HBox();
252 for (output_list::const_iterator i = output.begin(), end = output.end();
255 Gtk::Label *label = new Gtk::Label(*i);
258 int retval = sscanf (label->get_text().c_str(), "Gdk::Pixbuf %p", &ptr);
260 hbox->pack_start(*manage(label), Gtk::PACK_SHRINK, 0);
263 Glib::RefPtr<Gdk::Pixbuf> pic = Glib::wrap((GdkPixbuf*)ptr, true);
264 Gtk::Image *image = new Gtk::Image();
265 image->property_pixbuf() = pic;
266 hbox->pack_start(*manage(image), Gtk::PACK_SHRINK, 0);
276 // a series of functions which accept a format string on the form "text %1
277 // more %2 less %3" and a number of templated parameters and spits out the
279 template <typename T1>
280 inline Gtk::HBox* ucompose(const Glib::ustring &fmt, const T1 &o1)
282 UBoxPrivate::Composition c(fmt);
287 template <typename T1, typename T2>
288 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
289 const T1 &o1, const T2 &o2)
291 UBoxPrivate::Composition c(fmt);
296 template <typename T1, typename T2, typename T3>
297 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
298 const T1 &o1, const T2 &o2, const T3 &o3)
300 UBoxPrivate::Composition c(fmt);
301 c.arg(o1).arg(o2).arg(o3);
305 template <typename T1, typename T2, typename T3, typename T4>
306 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
307 const T1 &o1, const T2 &o2, const T3 &o3,
310 UBoxPrivate::Composition c(fmt);
311 c.arg(o1).arg(o2).arg(o3).arg(o4);
315 template <typename T1, typename T2, typename T3, typename T4, typename T5>
316 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
317 const T1 &o1, const T2 &o2, const T3 &o3,
318 const T4 &o4, const T5 &o5)
320 UBoxPrivate::Composition c(fmt);
321 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
325 template <typename T1, typename T2, typename T3, typename T4, typename T5,
327 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
328 const T1 &o1, const T2 &o2, const T3 &o3,
329 const T4 &o4, const T5 &o5, const T6 &o6)
331 UBoxPrivate::Composition c(fmt);
332 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
336 template <typename T1, typename T2, typename T3, typename T4, typename T5,
337 typename T6, typename T7>
338 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
339 const T1 &o1, const T2 &o2, const T3 &o3,
340 const T4 &o4, const T5 &o5, const T6 &o6,
343 UBoxPrivate::Composition c(fmt);
344 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
348 template <typename T1, typename T2, typename T3, typename T4, typename T5,
349 typename T6, typename T7, typename T8>
350 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
351 const T1 &o1, const T2 &o2, const T3 &o3,
352 const T4 &o4, const T5 &o5, const T6 &o6,
353 const T7 &o7, const T8 &o8)
355 UBoxPrivate::Composition c(fmt);
356 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
360 template <typename T1, typename T2, typename T3, typename T4, typename T5,
361 typename T6, typename T7, typename T8, typename T9>
362 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
363 const T1 &o1, const T2 &o2, const T3 &o3,
364 const T4 &o4, const T5 &o5, const T6 &o6,
365 const T7 &o7, const T8 &o8, const T9 &o9)
367 UBoxPrivate::Composition c(fmt);
368 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
372 template <typename T1, typename T2, typename T3, typename T4, typename T5,
373 typename T6, typename T7, typename T8, typename T9, typename T10>
374 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
375 const T1 &o1, const T2 &o2, const T3 &o3,
376 const T4 &o4, const T5 &o5, const T6 &o6,
377 const T7 &o7, const T8 &o8, const T9 &o9,
380 UBoxPrivate::Composition c(fmt);
381 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
386 template <typename T1, typename T2, typename T3, typename T4, typename T5,
387 typename T6, typename T7, typename T8, typename T9, typename T10,
389 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
390 const T1 &o1, const T2 &o2, const T3 &o3,
391 const T4 &o4, const T5 &o5, const T6 &o6,
392 const T7 &o7, const T8 &o8, const T9 &o9,
393 const T10 &o10, const T11 &o11)
395 UBoxPrivate::Composition c(fmt);
396 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
401 template <typename T1, typename T2, typename T3, typename T4, typename T5,
402 typename T6, typename T7, typename T8, typename T9, typename T10,
403 typename T11, typename T12>
404 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
405 const T1 &o1, const T2 &o2, const T3 &o3,
406 const T4 &o4, const T5 &o5, const T6 &o6,
407 const T7 &o7, const T8 &o8, const T9 &o9,
408 const T10 &o10, const T11 &o11, const T12 &o12)
410 UBoxPrivate::Composition c(fmt);
411 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
412 .arg(o10).arg(o11).arg(o12);
416 template <typename T1, typename T2, typename T3, typename T4, typename T5,
417 typename T6, typename T7, typename T8, typename T9, typename T10,
418 typename T11, typename T12, typename T13>
419 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
420 const T1 &o1, const T2 &o2, const T3 &o3,
421 const T4 &o4, const T5 &o5, const T6 &o6,
422 const T7 &o7, const T8 &o8, const T9 &o9,
423 const T10 &o10, const T11 &o11, const T12 &o12,
426 UBoxPrivate::Composition c(fmt);
427 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
428 .arg(o10).arg(o11).arg(o12).arg(o13);
432 template <typename T1, typename T2, typename T3, typename T4, typename T5,
433 typename T6, typename T7, typename T8, typename T9, typename T10,
434 typename T11, typename T12, typename T13, typename T14>
435 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
436 const T1 &o1, const T2 &o2, const T3 &o3,
437 const T4 &o4, const T5 &o5, const T6 &o6,
438 const T7 &o7, const T8 &o8, const T9 &o9,
439 const T10 &o10, const T11 &o11, const T12 &o12,
440 const T13 &o13, const T14 &o14)
442 UBoxPrivate::Composition c(fmt);
443 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
444 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
448 template <typename T1, typename T2, typename T3, typename T4, typename T5,
449 typename T6, typename T7, typename T8, typename T9, typename T10,
450 typename T11, typename T12, typename T13, typename T14,
452 inline Gtk::HBox* ucompose(const Glib::ustring &fmt,
453 const T1 &o1, const T2 &o2, const T3 &o3,
454 const T4 &o4, const T5 &o5, const T6 &o6,
455 const T7 &o7, const T8 &o8, const T9 &o9,
456 const T10 &o10, const T11 &o11, const T12 &o12,
457 const T13 &o13, const T14 &o14, const T15 &o15)
459 UBoxPrivate::Composition c(fmt);
460 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
461 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
467 #endif // BOX_UCOMPOSE_HPP