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

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