On Friday, 28 February 2020 at 12:21:41 UTC, Simen Kjærås wrote:
On Friday, 28 February 2020 at 10:33:11 UTC, Виталий Фадеев wrote:
Thanks all !
I happy !
Check this one:
    void On( T, M )( T o, M message )
    {
[snip]
    void main()
    {
        auto a = new A();
        a.Send( a, WM_KEYUP );
        a.Send( a, WM_KEYDOWN );
    }

That does mostly work, but fails for this code:

void main()
{
    Base a = new A();
    a.send( a, WM_KEYUP );
}

Basically, whenever you assign a derived to a base, this solution doesn't work, because T will be Base, not A.

I enjoyed with the previous code, so I wrote the code necessary to handle any WM_ message:

import core.sys.windows.windows;
import std.stdio;
import std.meta;

template startsWith(string prefix) {
enum startsWith(string s) = s.length >= prefix.length && s[0..prefix.length] == prefix;
}

enum getMessageValue(string s) = __traits(getMember, core.sys.windows.winuser, s);

// Get the all the WM_ messages
alias messageNames = Filter!(startsWith!"WM_", __traits(allMembers, core.sys.windows.winuser)); alias messageValues = NoDuplicates!(staticMap!(getMessageValue, messageNames));

class Base {
    LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
        switch (message) {
            foreach (msg; messageValues) {
                case msg:
if (auto that = cast(IMessageHandler!msg)this) {
                        return that.handle(wParam, lParam);
                    }
                    break;
            }
            default:
        }
        return 0;
    }
}

interface IMessageHandler(alias msg) {
mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, LPARAM lParam);");
    alias handle = mixin("On"~__traits(identifier, msg));
}

class Button : Base, IMessageHandler!WM_KEYDOWN, IMessageHandler!WM_SETTINGCHANGE {
    LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
        writeln("WM_KEYDOWN");
        return 0;
    }
    LRESULT OnWM_SETTINGCHANGE(WPARAM wParam, LPARAM lParam) {
        writeln("WM_SETTINGCHANGE");
        return 0;
    }
}

unittest {
    Base b1 = new Base();
    Base b2 = new Button();

    writeln("Base:");
// None of these will print anything, as Base doesn't handle them
    b1.On(WM_KEYDOWN, 0, 0);
    b1.On(WM_SETTINGCHANGE, 0, 0);
    b1.On(WM_DRAWITEM, 0, 0);
    writeln("Button:");
    b2.On(WM_KEYDOWN, 0, 0);
    b2.On(WM_SETTINGCHANGE, 0, 0);
// This will print nothing, as Button doesn't handle that message.
    b2.On(WM_DRAWITEM, 0, 0);
}

--
  Simen

Thank!

Today version is:

import core.sys.windows.windows;
import std.stdio;
import std.traits;
import std.conv : to;
import std.algorithm.searching : startsWith;


mixin template Eventable()
{
    override
    void On( UINT message )
    {
        // generate code in dispatcher
        // get AllMembers()
        //   filter OnABC (ex: OnWM_KEYUP)
        //   on each
        //   writeCode(
        //        if ( message == WM_KEYUP ) this.OnWM_KEYUP();
        //   );

foreach( methodName; __traits( allMembers, typeof( this ) ) )
        {
static if ( methodName.startsWith( "On" ) && methodName.length >= 3 )
            {
                mixin (
"if ( message == " ~ methodName[2..$] ~ " ) " ~ "this." ~ methodName ~ "();"
                );
            }
        }
    }
}


void Send( T, M )( T o, M message )
{
    o.On( message );
}


class Base
{
    void On( UINT message )
    {
        writeln( "Base.On() // default" );
    };
}


class A : Base
{
    mixin Eventable;

    void OnWM_KEYUP()
    {
        writeln( "A.OnWM_KEYUP()" );
    }

    void OnWM_KEYDOWN()
    {
        writeln( "A.OnWM_KEYDOWN()" );
    }
}


void main()
{
    auto a = new A();
    a.Send( WM_KEYUP );   // A

    auto c = cast(Base)a; // Base
    c.Send( WM_KEYUP );
}

// output:
// A.OnWM_KEYUP()
// A.OnWM_KEYUP()

Reply via email to