Changing active-state needs no color lookup
[ardour.git] / tools / icons / icon.cc
1 /*
2  * Copyright (C) 2019 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <cmath>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <getopt.h>
22 #include <iostream>
23 #include <unistd.h>
24
25 #include <cairo/cairo.h>
26
27 #include "pbd/xml++.h"
28 #include "gtkmm2ext/colors.h"
29 #include "widgets/ardour_icon.h"
30
31 using namespace ArdourWidgets;
32
33 static int  wh   = 64;
34 static int  sq   = 1;
35 static bool grid = false;
36
37 static uint32_t bg_color = 0x3d3d3dff; // gtk_background
38 static uint32_t fg_color = 0xeeeeecff; // gtk_foreground
39
40 static XMLNode*
41 find_named_node (const XMLNode& node, std::string name)
42 {
43         XMLNodeList nlist = node.children ();
44         for (XMLNodeConstIterator niter = nlist.begin (); niter != nlist.end (); ++niter) {
45                 XMLNode* child = *niter;
46                 if (child->name () == name) {
47                         return child;
48                 }
49         }
50         return 0;
51 }
52
53 static std::string
54 find_color_alias (const XMLNode& node, std::string colorname)
55 {
56         XMLNodeList nlist = node.children ();
57         for (XMLNodeConstIterator niter = nlist.begin (); niter != nlist.end (); ++niter) {
58                 XMLNode* child = *niter;
59                 if (child->name () != "ColorAlias") {
60                         continue;
61                 }
62                 XMLProperty const* name  = child->property ("name");
63                 XMLProperty const* alias = child->property ("alias");
64                 if (!name || !alias) {
65                         continue;
66                 }
67                 if (name->value () == colorname) {
68                         return alias->value ();
69                 }
70         }
71         return "";
72 }
73
74 static uint32_t
75 lookup_aliased_color (const XMLNode& node, std::string aliasname)
76 {
77         XMLNodeList nlist = node.children ();
78         for (XMLNodeConstIterator niter = nlist.begin (); niter != nlist.end (); ++niter) {
79                 XMLNode* child = *niter;
80                 if (child->name () != "Color") {
81                         continue;
82                 }
83                 XMLProperty const* name  = child->property ("name");
84                 XMLProperty const* color = child->property ("value");
85                 if (!name || !color) {
86                         continue;
87                 }
88                 if (name->value () == aliasname) {
89                         return strtoul (color->value ().c_str (), 0, 16);
90                 }
91         }
92         return 0;
93 }
94
95 static bool
96 load_colors (const char* path)
97 {
98         XMLTree tree;
99         if (!tree.read (path)) {
100                 return false;
101         }
102         XMLNode* colors  = find_named_node (*tree.root (), "Colors");
103         XMLNode* aliases = find_named_node (*tree.root (), "ColorAliases");
104
105         if (!colors || !aliases) {
106                 return false;
107         }
108
109         bg_color = lookup_aliased_color (*colors, find_color_alias (*aliases, "gtk_background"));
110         fg_color = lookup_aliased_color (*colors, find_color_alias (*aliases, "gtk_foreground"));
111
112         printf ("Theme colors bg:0x%x fg:0x%x\n", bg_color, fg_color);
113         return true;
114 }
115
116 static void
117 draw_icon (cairo_t* cr, int pos, const enum ArdourIcon::Icon icon, const Gtkmm2ext::ActiveState state)
118 {
119         int col = pos % sq;
120         int row = pos / sq;
121         cairo_save (cr);
122         cairo_translate (cr, col * wh, row * wh);
123         if (grid) {
124                 cairo_rectangle (cr, .5, .5, wh - 1, wh - 1);
125                 cairo_set_line_width (cr, 1);
126                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
127                 cairo_stroke (cr);
128                 cairo_move_to (cr, wh * .5, 0);
129                 cairo_line_to (cr, wh * .5, wh);
130                 cairo_move_to (cr, 0, wh * .5);
131                 cairo_line_to (cr, wh, wh * .5);
132                 cairo_stroke (cr);
133         }
134         ArdourIcon::render (cr, icon, wh, wh, state, fg_color);
135         cairo_restore (cr);
136 }
137
138 int
139 main (int argc, char** argv)
140 {
141         const char* fn = "/tmp/ardour_icons.png";
142
143         int c = 0;
144         while (EOF != (c = getopt (argc, argv, "go:s:t:"))) {
145                 switch (c) {
146                         case 'g':
147                                 grid = true;
148                                 break;
149                         case 't':
150                                 if (!load_colors (optarg)) {
151                                         std::cerr << "Error: failed to load color theme.\n";
152                                         ::exit (EXIT_FAILURE);
153                                 }
154                                 break;
155                         case 'o':
156                                 fn = optarg;
157                                 break;
158                         case 's':
159                                 wh = atoi (optarg);
160                                 break;
161                         default:
162                                 std::cerr << "Error: unrecognized option.\n";
163                                 ::exit (EXIT_FAILURE);
164                                 break;
165                 }
166         }
167
168         if (optind < argc) {
169                 std::cerr << "Error: Extra commandline argument.\n";
170                 ::exit (EXIT_FAILURE);
171         }
172
173         if (wh <= 0 || wh > 256) {
174                 wh = 64;
175         }
176
177         sq = ceil (sqrt (ArdourIcon::NoIcon + 3));
178
179         cairo_surface_t* cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, wh * sq, wh * sq);
180         cairo_t*         cr = cairo_create (cs);
181
182         Gtkmm2ext::set_source_rgba (cr, bg_color);
183         cairo_paint (cr);
184
185         int pos = 0;
186
187         draw_icon (cr, pos++, ArdourIcon::RecButton, Gtkmm2ext::Off);
188         draw_icon (cr, pos++, ArdourIcon::RecTapeMode, Gtkmm2ext::Off);
189         draw_icon (cr, pos++, ArdourIcon::RecButton, Gtkmm2ext::ImplicitActive);
190         draw_icon (cr, pos++, ArdourIcon::RecTapeMode, Gtkmm2ext::ImplicitActive);
191
192         for (int i = 0; i < ArdourIcon::NoIcon; ++i) {
193                 draw_icon (cr, pos++, ArdourIcon::Icon (i), Gtkmm2ext::ExplicitActive);
194         }
195
196         if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png (cs, fn)) {
197                 std::cerr << "Error: Failed to write to '" << fn << "'.\n";
198                 ::exit (EXIT_FAILURE);
199         }
200         cairo_destroy (cr);
201         cairo_surface_destroy (cs);
202         return 0;
203 }