source: branches/gcc/SL/ITEM_SHADER/item_shader.cxx

Last change on this file was 19810, checked in by westram, 3 weeks ago
File size: 25.2 KB
Line 
1// ============================================================ //
2//                                                              //
3//   File      : item_shader.cxx                                //
4//   Purpose   :                                                //
5//                                                              //
6//   Coded by Ralf Westram (coder@reallysoft.de) in June 2016   //
7//   http://www.arb-home.de/                                    //
8//                                                              //
9// ============================================================ //
10
11#include "item_shader.h"
12#include <arbdb.h>
13
14#define is_assert(cond) arb_assert(cond)
15
16static const ItemShader *findItemShader(const char *id);
17
18#if defined(UNIT_TESTS)
19static void destroyAllItemShaders();
20#endif
21
22// --------------------------------------------------------------------------------
23// test my interface
24
25#ifdef UNIT_TESTS
26#ifndef TEST_UNIT_H
27#include <test_unit.h>
28#endif
29
30struct DummyPlugin: public ShaderPlugin {
31    DummyPlugin() : ShaderPlugin("dummy", "test crash dummy") {}
32    ShadedValue shade(GBDATA */*gb_item*/) const OVERRIDE { return NULp; }
33    static void reshade() {}
34    int get_dimension() const OVERRIDE { return 0; }
35    void init_specific_awars(AW_root *) OVERRIDE {}
36    bool customizable() const OVERRIDE { return false; }
37    void customize(AW_root */*awr*/) OVERRIDE { is_assert(0); }
38    char *store_config() const OVERRIDE { return NULp; }
39    void load_or_reset_config(const char *) OVERRIDE {}
40    void activate(bool /*on*/) OVERRIDE {}
41};
42
43void TEST_shader_interface() {
44    GB_shell  shell;
45    GBDATA   *gb_main = GB_open("nosuch.arb", "c");
46
47    {
48        const char    *SHADY   = "lady";
49        AW_root       *NOROOT  = NULp;
50        AW_gc_manager *NOGCMAN = NULp;
51
52        BoundItemSel      sel(gb_main, SPECIES_get_selector());
53        ItemShader   *shader = registerItemShader(NOROOT, NOGCMAN, sel, SHADY, "undescribed", "", DummyPlugin::reshade, 0);
54        TEST_REJECT_NULL(shader);
55
56        const ItemShader *unknown = findItemShader("unknown");
57        TEST_EXPECT_NULL(unknown);
58
59        const ItemShader *found = findItemShader(SHADY);
60        TEST_EXPECT_EQUAL(found, shader);
61
62        // check shader plugins
63        shader->register_plugin(new DummyPlugin);
64        TEST_EXPECT(shader->activate_plugin  ("dummy"));        TEST_EXPECT_EQUAL(shader->active_plugin_name(), "dummy");
65        TEST_REJECT(shader->activate_plugin  ("unregistered")); TEST_EXPECT_EQUAL(shader->active_plugin_name(), "dummy");
66        TEST_EXPECT(shader->activate_plugin  ("field"));        TEST_EXPECT_EQUAL(shader->active_plugin_name(), "field");
67        TEST_EXPECT(shader->deactivate_plugin());               TEST_EXPECT_EQUAL(shader->active_plugin_name(), NO_PLUGIN_SELECTED);
68        TEST_REJECT(shader->deactivate_plugin());
69
70        // clean-up
71        destroyAllItemShaders(); // tests destruction (not called explicitely in production code)
72    }
73    GB_close(gb_main);
74}
75
76#endif // UNIT_TESTS
77
78// --------------------------------------------------------------------------------
79// implementation
80
81#include "field_shader.h"
82
83#include <config_manager.hxx>
84
85#include <aw_root.hxx>
86#include <aw_window.hxx>
87#include <aw_awar.hxx>
88#include <aw_preset.hxx>
89#include <aw_select.hxx>
90#include <aw_msg.hxx>
91
92#include <vector>
93#include <string>
94#include <algorithm>
95
96
97using namespace std;
98
99typedef vector<ShaderPluginPtr> Plugins;
100
101#define AWAR_SELECTED_PLUGIN shader_awar("plugin")
102#define AWAR_SHOW_DIMENSION  tmp_shader_awar("dimension")
103
104#define AWAR_GUI_RANGE           tmp_shader_awar("range")
105#define AWAR_GUI_OVERLAY_GROUPS  tmp_shader_awar("groups")
106#define AWAR_GUI_OVERLAY_MARKED  tmp_shader_awar("marked")
107#define AWAR_GUI_PHASE_FREQ      tmp_shader_awar("phase")
108#define AWAR_GUI_PHASE_ALTER     tmp_shader_awar("alternate")
109#define AWAR_GUI_PHASE_PRESHIFT  tmp_shader_awar("preshift")
110#define AWAR_GUI_PHASE_POSTSHIFT tmp_shader_awar("postshift")
111
112#define AWAR_PLUGIN_RANGE           plugin_awar("range")
113#define AWAR_PLUGIN_OVERLAY_GROUPS  plugin_awar("groups")
114#define AWAR_PLUGIN_OVERLAY_MARKED  plugin_awar("marked")
115#define AWAR_PLUGIN_PHASE_FREQ      plugin_awar("phase")
116#define AWAR_PLUGIN_PHASE_ALTER     plugin_awar("alternate")
117#define AWAR_PLUGIN_PHASE_PRESHIFT  plugin_awar("preshift")
118#define AWAR_PLUGIN_PHASE_POSTSHIFT plugin_awar("postshift")
119
120// ----------------------
121//      ShaderPlugin
122
123void ShaderPlugin::init_awars(AW_root *awr, const char *awar_prefix_) {
124    is_assert(awar_prefix.empty()); // called twice?
125    awar_prefix = string(awar_prefix_) + '/' + get_id();
126
127    if (awr) {
128        // common awars for all shader plugins:
129        awr->awar_string(AWAR_PLUGIN_RANGE,           "");  // => will use first available color-range (for dimension reported by actual plugin)
130        awr->awar_int   (AWAR_PLUGIN_OVERLAY_GROUPS,  0);
131        awr->awar_int   (AWAR_PLUGIN_OVERLAY_MARKED,  0);
132        awr->awar_float (AWAR_PLUGIN_PHASE_FREQ,      1.0);
133        awr->awar_int   (AWAR_PLUGIN_PHASE_ALTER,     0);
134        awr->awar_float (AWAR_PLUGIN_PHASE_PRESHIFT,  0.0);
135        awr->awar_float (AWAR_PLUGIN_PHASE_POSTSHIFT, 0.0);
136
137        init_specific_awars(awr);
138    }
139}
140
141bool ShaderPlugin::overlay_marked() const {
142    return AW_root::SINGLETON->awar(AWAR_PLUGIN_OVERLAY_MARKED)->read_int();
143}
144bool ShaderPlugin::overlay_color_groups() const {
145    return AW_root::SINGLETON->awar(AWAR_PLUGIN_OVERLAY_GROUPS)->read_int();
146}
147
148// -------------------------
149//      ItemShader_impl
150
151#define SKIP_TMP_PREFIX 4
152
153class ItemShader_impl FINAL_TYPE : public ItemShader {
154    Plugins plugins;
155    string  help_id;
156    string  awar_prefix;
157
158    RefPtr<AW_gc_manager>         gcman;
159    RefPtr<AW_window>             aw_cfg;            // config window
160    RefPtr<AW_option_menu_struct> range_option_menu; // color-range selector in config window
161
162    ShaderPluginPtr find_plugin(const string& plugin_id) const;
163
164    void setup_new_dimension();
165    void init_config_definition(AWT_config_definition& cdef, bool add_selected_plugin) const;
166
167public:
168    ItemShader_impl(AW_gc_manager *gcman_, const string& id_, const string& description_, const string& help_id_, ReshadeCallback rcb, int undef_gc) :
169        ItemShader(id_, description_, rcb, undef_gc),
170        help_id(help_id_),
171        awar_prefix(GBS_global_string("tmp/shader/%s", get_id().c_str())),
172        gcman(gcman_),
173        aw_cfg(NULp),
174        range_option_menu(NULp)
175    {}
176
177    void register_plugin(ShaderPluginPtr plugin) OVERRIDE;
178    bool activate_plugin(const string& plugin_id) OVERRIDE;
179    bool activate_plugin_impl(const string& plugin_id);
180    std::string active_plugin_name() const OVERRIDE {
181        if (active_plugin.isSet()) return active_plugin->get_id();
182        return NO_PLUGIN_SELECTED;
183    }
184
185    const char *shader_awar(const char *name) const {
186        return GBS_global_string("%s/%s", awar_prefix.c_str()+SKIP_TMP_PREFIX, name);
187    }
188    const char *tmp_shader_awar(const char *name) const {
189        return GBS_global_string("%s/%s", awar_prefix.c_str(), name);
190    }
191
192    void init_awars(AW_root *awr);
193    void init() OVERRIDE;
194
195    void check_dimension_change() OVERRIDE;
196
197    void popup_config_window(AW_root *awr) OVERRIDE;
198
199    static void trigger_reshade_cb(AW_root*,ItemShader_impl *shader) { shader->trigger_reshade_callback(SIMPLE_RESHADE); }
200
201    void configure_active_plugin(AW_root *awr) {
202        if (active_plugin.isSet()) {
203            if (active_plugin->customizable()) active_plugin->customize(awr);
204            else aw_message(GBS_global_string("Nothing to configure for '%s'", active_plugin->get_description().c_str()));
205        }
206        else aw_message("Please select a shader");
207    }
208    static void configure_active_plugin_cb(AW_window *aww, ItemShader_impl *shader) { shader->configure_active_plugin(aww->get_root()); }
209
210    void selected_plugin_changed_cb(AW_root *awr) {
211        AW_awar *awar_plugin = awr->awar(AWAR_SELECTED_PLUGIN);
212        if (!activate_plugin_impl(awar_plugin->read_char_pntr())) {
213            awar_plugin->write_string(NO_PLUGIN_SELECTED);
214        }
215    }
216    static void selected_plugin_changed_cb(AW_root *awr, ItemShader_impl *shader) { shader->selected_plugin_changed_cb(awr); }
217
218    void selected_range_changed_cb(AW_root *awr) {
219        AW_activateColorRange(gcman, awr->awar(AWAR_GUI_RANGE)->read_char_pntr());
220        trigger_reshade_callback(SIMPLE_RESHADE);
221    }
222    static void selected_range_changed_cb(AW_root *awr, ItemShader_impl *shader) { shader->selected_range_changed_cb(awr); }
223
224    void configure_colors_cb(AW_window *aww) { AW_popup_gc_color_range_window(aww, gcman); }
225    static void configure_colors_cb(AW_window *aww, ItemShader_impl *shader) { shader->configure_colors_cb(aww); }
226
227    void phase_changed_cb(AW_root *awr) {
228        phaser = Phaser(awr->awar(AWAR_GUI_PHASE_FREQ)->read_float(),
229                        awr->awar(AWAR_GUI_PHASE_ALTER)->read_int(),
230                        awr->awar(AWAR_GUI_PHASE_PRESHIFT)->read_float(),
231                        awr->awar(AWAR_GUI_PHASE_POSTSHIFT)->read_float());
232        trigger_reshade_callback(SIMPLE_RESHADE);
233    }
234    static void phase_changed_cb(AW_root *awr, ItemShader_impl *shader) { shader->phase_changed_cb(awr); }
235
236    void reset_phasing_cb(AW_root *awr) const {
237        DelayReshade here(this);
238        awr->awar(AWAR_GUI_PHASE_FREQ)->reset_to_default();
239        awr->awar(AWAR_GUI_PHASE_ALTER)->reset_to_default();
240        awr->awar(AWAR_GUI_PHASE_PRESHIFT)->reset_to_default();
241        awr->awar(AWAR_GUI_PHASE_POSTSHIFT)->reset_to_default();
242    }
243    static void reset_phasing_cb(AW_window *aww, const ItemShader_impl *shader) { shader->reset_phasing_cb(aww->get_root()); }
244
245    char *store_config_cb() const;
246    void  load_or_reset_config_cb(const char *cfgstr);
247
248    static char *store_config_cb(ItemShader_impl *shader) { return shader->store_config_cb(); }
249    static void load_or_reset_config_cb(const char *cfgstr, ItemShader_impl *shader) { return shader->load_or_reset_config_cb(cfgstr); }
250};
251
252struct has_id {
253    string id;
254    explicit has_id(const char *id_) : id(id_) {}
255    explicit has_id(const string& id_) : id(id_) {}
256
257    bool operator()(const ItemShader_impl& shader) { return shader.get_id() == id; }
258    bool operator()(const ShaderPluginPtr& plugin) { return plugin->get_id() == id; }
259};
260
261
262// --------------------------------
263//      shader plugin registry
264
265ShaderPluginPtr ItemShader_impl::find_plugin(const string& plugin_id) const {
266    Plugins::const_iterator found = find_if(plugins.begin(), plugins.end(), has_id(plugin_id));
267    return found == plugins.end() ? ShaderPluginPtr() : *found;
268}
269
270void ItemShader_impl::register_plugin(ShaderPluginPtr plugin) {
271    is_assert(find_plugin(plugin->get_id()).isNull()); // attempt to register two plugins with same name!
272    plugins.push_back(plugin);
273
274    plugin->announce_shader(this);
275    plugin->init_awars(AW_root::SINGLETON, awar_prefix.c_str()+SKIP_TMP_PREFIX);
276}
277
278bool ItemShader_impl::activate_plugin_impl(const string& plugin_id) {
279    bool            changed    = false;
280    ShaderPluginPtr prevActive = active_plugin;
281    if (plugin_id == NO_PLUGIN_SELECTED) {
282        if (active_plugin.isSet()) {
283            active_plugin.setNull();
284            changed = true;
285        }
286    }
287    else {
288        ShaderPluginPtr found = find_plugin(plugin_id);
289        if (found.isSet()) {
290            active_plugin = found;
291            changed       = true;
292        }
293    }
294    if (changed) {
295        if (prevActive.isSet()) prevActive->activate(false);
296        if (active_plugin.isSet()) active_plugin->activate(true);
297
298        DelayReshade here(this);
299
300        AW_root *awr = AW_root::SINGLETON;
301        if (awr) {
302            if (active_plugin.isSet()) {
303                // map common GUI awars to awars of active plugin:
304                awr->awar(AWAR_GUI_RANGE)          ->map(active_plugin->AWAR_PLUGIN_RANGE);
305                awr->awar(AWAR_GUI_OVERLAY_MARKED) ->map(active_plugin->AWAR_PLUGIN_OVERLAY_MARKED);
306                awr->awar(AWAR_GUI_OVERLAY_GROUPS) ->map(active_plugin->AWAR_PLUGIN_OVERLAY_GROUPS);
307                awr->awar(AWAR_GUI_PHASE_FREQ)     ->map(active_plugin->AWAR_PLUGIN_PHASE_FREQ);
308                awr->awar(AWAR_GUI_PHASE_ALTER)    ->map(active_plugin->AWAR_PLUGIN_PHASE_ALTER);
309                awr->awar(AWAR_GUI_PHASE_PRESHIFT) ->map(active_plugin->AWAR_PLUGIN_PHASE_PRESHIFT);
310                awr->awar(AWAR_GUI_PHASE_POSTSHIFT)->map(active_plugin->AWAR_PLUGIN_PHASE_POSTSHIFT);
311                check_dimension_change();
312            }
313            else {
314                // unmap GUI awars:
315                awr->awar(AWAR_GUI_RANGE)          ->unmap();
316                awr->awar(AWAR_GUI_OVERLAY_MARKED) ->unmap();
317                awr->awar(AWAR_GUI_OVERLAY_GROUPS) ->unmap();
318                awr->awar(AWAR_GUI_PHASE_FREQ)     ->unmap();
319                awr->awar(AWAR_GUI_PHASE_ALTER)    ->unmap();
320                awr->awar(AWAR_GUI_PHASE_PRESHIFT) ->unmap();
321                awr->awar(AWAR_GUI_PHASE_POSTSHIFT)->unmap();
322                setup_new_dimension();
323            }
324        }
325        trigger_reshade_callback(SIMPLE_RESHADE);
326    }
327    return changed;
328}
329bool ItemShader_impl::activate_plugin(const string& plugin_id) {
330    AW_root *awr = AW_root::SINGLETON;
331    if (!awr) {
332        return activate_plugin_impl(plugin_id);
333    }
334
335    AW_awar *awar_plugin = awr->awar(AWAR_SELECTED_PLUGIN);
336    awar_plugin->write_string(plugin_id.c_str());
337
338    return strcmp(awar_plugin->read_char_pntr(), plugin_id.c_str()) == 0;
339}
340
341// --------------------------
342//      dimension change
343
344void ItemShader_impl::setup_new_dimension() {
345    AW_root *awr = AW_root::SINGLETON;
346    int      dim = active_plugin.isSet() ? active_plugin->get_dimension() : 0;
347
348    AW_awar *awar_range = awr->awar(AWAR_GUI_RANGE);
349
350    if (dim>0) {
351        // auto-select another color-range (if selected does not match dimension)
352
353        ConstStrArray ids, names;
354        AW_getColorRangeNames(gcman, dim, ids, names);
355        aw_assert(!ids.empty()); // no range defined with dimension 'dim' // @@@ check during ItemShader-setup!
356
357        const char *selected_range_id  = awar_range->read_char_pntr();
358        bool        seen_selected      = false;
359
360        if (aw_cfg) aw_cfg->clear_option_menu(range_option_menu);
361        for (unsigned i = 0; i<ids.size(); ++i) {
362            if (aw_cfg) aw_cfg->insert_option(names[i], "", ids[i]);
363            if (!seen_selected && strcmp(selected_range_id, ids[i]) == 0) { // check if awar-value exists
364                seen_selected = true;
365            }
366        }
367        if (aw_cfg) aw_cfg->update_option_menu();
368
369        if (!seen_selected) selected_range_id = ids[0]; // autoselect first color-range
370
371        awar_range->write_string(selected_range_id);
372        AW_activateColorRange(gcman, selected_range_id);
373    }
374    else {
375        if (aw_cfg) {
376            aw_cfg->clear_option_menu(range_option_menu);
377            aw_cfg->insert_option("<none>", "", "");
378            aw_cfg->update_option_menu();
379        }
380        awar_range->write_string("");
381    }
382
383    awr->awar(AWAR_SHOW_DIMENSION)->write_int(dim);
384}
385void ItemShader_impl::check_dimension_change() {
386    aw_assert(active_plugin.isSet());
387
388    int wanted_dim = active_plugin->get_dimension();
389    if (wanted_dim>0) {
390        int         range_dim;
391        /*const char *range_id = */ AW_getActiveColorRangeID(gcman, &range_dim);
392
393        int awar_dim = AW_root::SINGLETON->awar(AWAR_SHOW_DIMENSION)->read_int();
394
395        if (wanted_dim != range_dim || wanted_dim != awar_dim) { // active color-range has wrong dimension (or config window needs update)
396            setup_new_dimension();
397        }
398    }
399}
400
401// ---------------------------------------
402//      store / restore shader config
403
404void ItemShader_impl::init_config_definition(AWT_config_definition& cdef, bool add_selected_plugin) const {
405    if (add_selected_plugin) cdef.add(AWAR_SELECTED_PLUGIN, "plugin");
406
407    cdef.add(AWAR_GUI_RANGE,           "range");
408    cdef.add(AWAR_GUI_OVERLAY_GROUPS,  "overlay_groups");
409    cdef.add(AWAR_GUI_OVERLAY_MARKED,  "overlay_marked");
410    cdef.add(AWAR_GUI_PHASE_FREQ,      "phase_frequency");
411    cdef.add(AWAR_GUI_PHASE_ALTER,     "phase_alternate");
412    cdef.add(AWAR_GUI_PHASE_PRESHIFT,  "phase_preshift");
413    cdef.add(AWAR_GUI_PHASE_POSTSHIFT, "phase_postshift");
414}
415
416char *ItemShader_impl::store_config_cb() const {
417    char     *cfgstr = NULp;
418    GB_ERROR  error  = NULp;
419
420    AWT_config_definition cdef;
421    init_config_definition(cdef, true);
422    {
423        AWT_config cfg(&cdef);
424        error = cfg.parseError();
425
426        if (!error) {
427            if (active_plugin.isSet()) {
428                char *plugin_setup = active_plugin->store_config();
429                if (plugin_setup) {
430                    cfg.set_entry("plugin_setup", plugin_setup);
431                    free(plugin_setup);
432                }
433            }
434            cfgstr = cfg.config_string();
435        }
436    }
437
438    aw_message_if(error);
439
440    return cfgstr ? cfgstr : strdup("");
441}
442
443void ItemShader_impl::load_or_reset_config_cb(const char *stored) {
444    GB_ERROR error = NULp;
445
446    AWT_config_definition cdef;
447    init_config_definition(cdef, stored);
448
449    if (stored) {
450        AWT_config cfg(stored);
451        error = cfg.parseError();
452
453        if (!error) {
454            char *plugin_setup = nulldup(cfg.get_entry("plugin_setup"));
455            cfg.delete_entry("plugin_setup"); // avoids wrong error message about unsupported entry 'plugin_setup'
456
457            const char      *saved_pluginname = cfg.get_entry("plugin");
458            ShaderPluginPtr  targetPlugin     = saved_pluginname ? find_plugin(saved_pluginname) : active_plugin;
459
460            {
461                DelayReshade here(this);
462                if (plugin_setup) {
463                    if (targetPlugin.isSet()) {
464                        // restore plugin specific settings
465                        targetPlugin->load_or_reset_config(plugin_setup);
466                    }
467                    else {
468                        error = "Failed to restore plugin-specific settings (unknown plugin)";
469                    }
470                }
471
472                // activate saved plugin before restoring its settings
473                // (otherwise settings of the previously selected plugin may get modified)
474                if (targetPlugin.isSet()) activate_plugin(targetPlugin->get_id());
475
476                // now restore all settings (into GUI-awars mapped to active config)
477                cfg.write_to_awars(cdef.get_mapping(), true);
478            }
479            free(plugin_setup);
480        }
481    }
482    else { // reset
483        DelayReshade here(this);
484        if (active_plugin.isSet()) active_plugin->load_or_reset_config(NULp); // reset selected plugin-config first
485        cdef.reset();                                                         // will NOT touch selected plugin (ie. its only a partial restore)
486    }
487    aw_message_if(error);
488}
489
490// ------------------------
491//      user-interface
492
493static void global_colorgroup_use_changed_cb(AW_root *awr, ItemShader_impl *shader) {
494    awr->awar(shader->AWAR_GUI_OVERLAY_GROUPS)->write_int(awr->awar(AW_get_color_groups_active_awarname())->read_int());
495}
496
497void ItemShader_impl::init() {
498    // initialize ItemShader
499    // - activate plugin stored in AWAR
500
501    is_assert(!plugins.empty()); // you have to register all plugins before calling init
502
503    first_range_gc = AW_getFirstRangeGC(gcman);
504    selected_plugin_changed_cb(AW_root::SINGLETON, this);
505}
506
507void ItemShader_impl::init_awars(AW_root *awr) {
508    RootCallback Reshade_cb       = makeRootCallback(ItemShader_impl::trigger_reshade_cb, this);
509    RootCallback PhaseChanged_cb  = makeRootCallback(ItemShader_impl::phase_changed_cb, this);
510    RootCallback PluginChanged_cb = makeRootCallback(ItemShader_impl::selected_plugin_changed_cb, this);
511    RootCallback RangeChanged_cb  = makeRootCallback(ItemShader_impl::selected_range_changed_cb, this);
512
513    awr->awar_string(AWAR_SELECTED_PLUGIN,     NO_PLUGIN_SELECTED)->add_callback(PluginChanged_cb);
514    awr->awar_int   (AWAR_SHOW_DIMENSION,      -1);
515    awr->awar_string(AWAR_GUI_RANGE,           "") ->add_callback(RangeChanged_cb);
516    awr->awar_int   (AWAR_GUI_OVERLAY_GROUPS,  0)  ->add_callback(Reshade_cb);
517    awr->awar_int   (AWAR_GUI_OVERLAY_MARKED,  0)  ->add_callback(Reshade_cb);
518    awr->awar_float (AWAR_GUI_PHASE_FREQ,      1.0)->set_minmax(0.01, 100.0)->add_callback(PhaseChanged_cb);
519    awr->awar_float (AWAR_GUI_PHASE_PRESHIFT,  0.0)->set_minmax(0.0,    1.0)->add_callback(PhaseChanged_cb);
520    awr->awar_float (AWAR_GUI_PHASE_POSTSHIFT, 0.0)->set_minmax(0.0,    1.0)->add_callback(PhaseChanged_cb);
521    awr->awar_int   (AWAR_GUI_PHASE_ALTER,     0)  ->add_callback(PhaseChanged_cb);
522
523    const char *awarname_global_colorgroups = AW_get_color_groups_active_awarname();
524    awr->awar(awarname_global_colorgroups)->add_callback(makeRootCallback(global_colorgroup_use_changed_cb, this));
525}
526
527void ItemShader_impl::popup_config_window(AW_root *awr) {
528    if (!aw_cfg) {
529        AW_window_simple *aws = new AW_window_simple;
530        {
531            string wid = GBS_global_string("shader_cfg_%s", get_id().c_str());
532            aws->init(awr, wid.c_str(), get_description().c_str());
533        }
534        aws->load_xfig("item_shader_cfg.fig");
535
536        aws->button_length(8);
537
538        aws->at("close");
539        aws->callback(AW_POPDOWN);
540        aws->create_button("CLOSE", "CLOSE", "O");
541
542        aws->at("help");
543        aws->callback(makeHelpCallback(help_id.c_str()));
544        aws->create_button("HELP", "HELP");
545
546        aws->at("plugin");
547        AW_selection_list *sel = aws->create_selection_list(AWAR_SELECTED_PLUGIN);
548        sel->insert_default("<No shading>", NO_PLUGIN_SELECTED);
549        for (Plugins::iterator p = plugins.begin(); p != plugins.end(); ++p) {
550            const ShaderPlugin& plugged = **p;
551            sel->insert(plugged.get_description().c_str(), plugged.get_id().c_str());
552        }
553        sel->update();
554
555        aws->at("plugin_cfg");
556        aws->callback(makeWindowCallback(ItemShader_impl::configure_active_plugin_cb, this));
557        aws->create_autosize_button("configure", "Configure");
558
559        aws->at("range");
560        range_option_menu = aws->create_option_menu(AWAR_GUI_RANGE);
561        aws->insert_option("<none>", "", "");
562        aws->update_option_menu();
563
564        aws->at("color_cfg");
565        aws->callback(makeWindowCallback(ItemShader_impl::configure_colors_cb, this));
566        aws->create_autosize_button("color_cfg", "Color setup");
567
568        aws->at("groups");
569        aws->create_toggle(AWAR_GUI_OVERLAY_GROUPS);
570
571        aws->at("marked");
572        aws->create_toggle(AWAR_GUI_OVERLAY_MARKED);
573
574        aws->auto_space(5,5);
575        const int FIELDSIZE    = 12;
576        const int SCALERLENGTH = 400;
577
578        aws->at("alt");
579        aws->create_toggle(AWAR_GUI_PHASE_ALTER);
580
581        aws->at("dim");
582        aws->create_button(NULp, AWAR_SHOW_DIMENSION, NULp, "+");
583
584        aws->at("reset");
585        aws->callback(makeWindowCallback(ItemShader_impl::reset_phasing_cb, this));
586        aws->create_button("reset", "RESET", "R");
587
588        aws->at("freq");      aws->create_input_field_with_scaler(AWAR_GUI_PHASE_FREQ,      FIELDSIZE, SCALERLENGTH, AW_SCALER_EXP_LOWER);
589        aws->at("preshift");  aws->create_input_field_with_scaler(AWAR_GUI_PHASE_PRESHIFT,  FIELDSIZE, SCALERLENGTH, AW_SCALER_LINEAR);
590        aws->at("postshift"); aws->create_input_field_with_scaler(AWAR_GUI_PHASE_POSTSHIFT, FIELDSIZE, SCALERLENGTH, AW_SCALER_LINEAR);
591
592        aws->at("cfg");
593        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, get_id().c_str(),
594                                  makeStoreConfigCallback(ItemShader_impl::store_config_cb, this),
595                                  makeRestoreConfigCallback(ItemShader_impl::load_or_reset_config_cb, this));
596
597        aws->window_fit();
598
599        aw_cfg = aws;
600
601        setup_new_dimension();
602    }
603    aw_cfg->activate();
604}
605
606// -------------------------
607//      shader registry
608
609typedef vector<ItemShader_impl> Shaders;
610
611static Shaders registered;
612
613ItemShader *registerItemShader(AW_root *awr, AW_gc_manager *gcman, BoundItemSel& itemtype, const char *unique_id, const char *description, const char *help_id, ReshadeCallback reshade_cb, int undef_gc) {
614    /*! create a new ItemShader
615     *
616     * @param awr             the application root
617     * @param gcman           gc-manager used for shading
618     * @param itemtype        type of item
619     * @param unique_id       unique ID
620     * @param description     short description used ia. as title of config window (eg. "Tree shading")
621     * @param help_id         helpfile
622     * @param reshade_cb      callback which updates the shading + refreshes the display
623     * @param undef_gc        GC reported for undefined ShadedValue
624     *
625     * (Note: the reshade_cb may be called very often! best is to trigger a temp. DB-awar like AWAR_TREE_RECOMPUTE)
626     */
627    if (findItemShader(unique_id)) {
628        is_assert(0); // duplicate shader id
629        return NULp;
630    }
631
632    registered.push_back(ItemShader_impl(gcman, unique_id, description, help_id, reshade_cb, undef_gc));
633    ItemShader_impl& new_shader = registered.back();
634    if (awr) new_shader.init_awars(awr);
635    new_shader.register_plugin(makeItemFieldShader(itemtype));
636    return &new_shader;
637}
638
639static const ItemShader *findItemShader(const char *id) {
640    Shaders::iterator found = find_if(registered.begin(), registered.end(), has_id(id));
641    return found == registered.end() ? NULp : &*found;
642}
643
644#if defined(UNIT_TESTS) // atm only used locally in unittest code
645static void destroyAllItemShaders() {
646    registered.clear();
647}
648#endif
649
Note: See TracBrowser for help on using the repository browser.