Re: Call method if declared only

2020-03-01 Thread Alexandru Ermicioi via Digitalmars-d-learn

On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:

How to implement ?


I would go for a template mixin that implements send operation in 
each subclass. Sine template mixin's content is declared in scope 
of declaration not template's module, the code inside it is aware 
of concrete implementation of your base class, and could 
introspect all methods available in it, and generate your switch 
statement (in send operation) for all supported messages.


This would be just one line of code in each class with no 
complication whatsoever.


Best regards,
Alexandru.


Re: Call method if declared only

2020-02-29 Thread Виталий Фадеев via Digitalmars-d-learn

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()



Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

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


Re: Call method if declared only

2020-02-28 Thread Виталий Фадеев via Digitalmars-d-learn

On Friday, 28 February 2020 at 10:20:03 UTC, Виталий Фадеев wrote:
On Friday, 28 February 2020 at 10:14:41 UTC, Виталий Фадеев 
wrote:
On Friday, 28 February 2020 at 09:49:53 UTC, Simen Kjærås 
wrote:
On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев 
wrote:

[...]


So let's create a template for that:

[...]


Cool!


Think!
I writing code generation. Like this:

void On( T, alias M )( T o )
{
// generate code in dispatcher
// get AllMembers()
//   filter OnABC (ex: OnWM_KEYUP)
//   on each
//   writeCode(
// q{
//if ( message == WM_KEYUP )
//   o.OnWM_KEYUP();
//  }
//   );

static ... foreach(  ) ...
{
CB_MESSAGE = ...
CB_METHOD  = ...

mixin (
"if ( message == CB_MESSAGE ) " ~ "o." ~ CB_METHOD 
~ "();"

);
}
}


Thanks all !
I happy !
Check this one:

import core.sys.windows.windows;
import std.stdio;
import std.traits;
import std.algorithm.searching;


void On( T, M )( T o, M message )
{
// generate code in dispatcher
// get AllMembers()
//   filter OnABC (ex: OnWM_KEYUP)
//   on each
//   writeCode(
// q{
//if ( message == WM_KEYUP )
//   o.OnWM_KEYUP();
//  }
//   );

foreach( methodName; __traits( allMembers, T ) )
{
static if ( methodName.startsWith( "On" ) && 
methodName.length >= 3 )

{
mixin (
"if ( message == " ~ methodName[2..$] ~ " ) " 
~ "o." ~ methodName ~ "();"

);
}
}
}


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

class A : Base
{
void OnWM_KEYUP()
{
writeln( "A.OnWM_KEYUP()" );
}

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


void main()
{
auto a = new A();
a.Send( a, WM_KEYUP );
a.Send( a, WM_KEYDOWN );
}





Re: Call method if declared only

2020-02-28 Thread Виталий Фадеев via Digitalmars-d-learn

On Friday, 28 February 2020 at 10:14:41 UTC, Виталий Фадеев wrote:

On Friday, 28 February 2020 at 09:49:53 UTC, Simen Kjærås wrote:
On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев 
wrote:

[...]


So let's create a template for that:

[...]


Cool!


Think!
I writing code generation. Like this:

void On( T, alias M )( T o )
{
// generate code in dispatcher
// get AllMembers()
//   filter OnABC (ex: OnWM_KEYUP)
//   on each
//   writeCode(
// q{
//if ( message == WM_KEYUP )
//   o.OnWM_KEYUP();
//  }
//   );

static ... foreach(  ) ...
{
CB_MESSAGE = ...
CB_METHOD  = ...

mixin (
"if ( message == CB_MESSAGE ) " ~ "o." ~ CB_METHOD ~ 
"();"

);
}
}



Re: Call method if declared only

2020-02-28 Thread Виталий Фадеев via Digitalmars-d-learn

On Friday, 28 February 2020 at 09:49:53 UTC, Simen Kjærås wrote:
On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев 
wrote:

[...]


So let's create a template for that:

[...]


Cool!


Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote:

Yes. Thank !
I read it.
Problem is - OS has many messages + user messages... It mean 
what interfaces like IKeyDown must me declared. All. Dream on 
write less code...


So let's create a template for that:

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

}

And use it:

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

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
if (auto that = 
cast(IMessageHandler!WM_KEYDOWN)this) {

return that.OnWM_KEYDOWN(wParam, lParam);
}
break;
default:
}
return 0;
}
}

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

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

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

You'll still have to specify for each derived class which 
messages they handle, but no need to define hundreds of 
interfaces separately.


--
  Simen



Re: Call method if declared only

2020-02-28 Thread drug via Digitalmars-d-learn

On 2/28/20 12:25 PM, Виталий Фадеев wrote:



Now I reading Template doc for up skill...



I recommend this nice tutorial 
https://github.com/PhilippeSigaud/D-templates-tutorial




Re: Call method if declared only

2020-02-28 Thread Виталий Фадеев via Digitalmars-d-learn

On Friday, 28 February 2020 at 09:12:38 UTC, Simen Kjærås wrote:
On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев 
wrote:

Searching solution for idea !


For whatever reason, it seems my attempts at answering this 
earlier has disappeared into the void. Here:


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

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
default:
}
return 0;
}

auto tryCall(string name, Args...)(Args args) {
import std.meta;

alias This = typeof(this);
alias module_ = __traits(parent, This);

enum isSubclass(T...) = is(T[0] : This);
alias getModuleMember(string name) = 
__traits(getMember, module_, name);

enum hasMethod(T) = __traits(hasMember, T, name);

// Get every member in this module
enum memberNames = __traits(allMembers, module_);
alias members = staticMap!(getModuleMember, 
memberNames);


// Filter away anything that isn't derived from Base
alias subclasses = Filter!(isSubclass, members);

// Get rid of anything that doesn't have a method with 
the correct name
alias subclassesWithMethod = Filter!(hasMethod, 
subclasses);


// Sort them so you get the most derived types first
alias Types = DerivedToFront!subclassesWithMethod;

// Check for each type if the `this` is an instance of 
that specific one

static foreach (T; Types) {
if (cast(T)this !is null) {
// And look up that method and call it.
return __traits(getMember, cast(T)this, 
name)(args);

}
}

// If `this` is not one of the types with that method, 
return some default value

return 0;
}
}

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

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

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

Now, this only works for subclasses defined in the same module. 
A possibly better solution would be interfaces:


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

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
if (cast(IKeyDown)this) {
return 
(cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam);

}
default:
}
return 0;
}
}

interface IKeyDown {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam);
}

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

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

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

--
  Simen


Yes. Thank !
I read it.
Problem is - OS has many messages + user messages... It mean what 
interfaces like IKeyDown must me declared. All. Dream on write 
less code...


Some like code generation. In message dispatcher. Like this:

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


template canOn( T, M )
{
enum string callbackName = "On" ~ __traits( identifier, M 
);


static if ( __traits( hasMember, T, callbackName ) )
enum canOn = isCallable!( __traits( getMember, T, 
callbackName ) );

else
enum canOn = false;
}

void maybeOn( T, alias M )( T o, M message )
{
enum string callbackName = "On" ~ __traits( identifier, M 
);


static if ( canOn!(T, M) )
__traits( getMember, T, callbackName )();
}


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


class Base
{
void Send( T, alias M )( T o, M message )
{
// generate code in dispatcher
// if ( canOn!( T, M ) )
//   writeCode(
// q{
//if ( message == WM_KEYUP )
//   o.OnWM_KEYUP();
//  }
//   );
o.On( message );
}
}

class A : Base
{
void OnWM_KEYUP()
{
writeln( "A.OnKey()" );
}
}


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


Here I have compile error... at
void On( T, alias M )( T o, M message )

Now I reading Template doc for up skill...

Thank!


Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:

Searching solution for idea !


For whatever reason, it seems my attempts at answering this 
earlier has disappeared into the void. Here:


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

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
default:
}
return 0;
}

auto tryCall(string name, Args...)(Args args) {
import std.meta;

alias This = typeof(this);
alias module_ = __traits(parent, This);

enum isSubclass(T...) = is(T[0] : This);
alias getModuleMember(string name) = __traits(getMember, 
module_, name);

enum hasMethod(T) = __traits(hasMember, T, name);

// Get every member in this module
enum memberNames = __traits(allMembers, module_);
alias members = staticMap!(getModuleMember, memberNames);

// Filter away anything that isn't derived from Base
alias subclasses = Filter!(isSubclass, members);

// Get rid of anything that doesn't have a method with 
the correct name
alias subclassesWithMethod = Filter!(hasMethod, 
subclasses);


// Sort them so you get the most derived types first
alias Types = DerivedToFront!subclassesWithMethod;

// Check for each type if the `this` is an instance of 
that specific one

static foreach (T; Types) {
if (cast(T)this !is null) {
// And look up that method and call it.
return __traits(getMember, cast(T)this, 
name)(args);

}
}

// If `this` is not one of the types with that method, 
return some default value

return 0;
}
}

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

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

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

Now, this only works for subclasses defined in the same module. A 
possibly better solution would be interfaces:


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

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
if (cast(IKeyDown)this) {
return 
(cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam);

}
default:
}
return 0;
}
}

interface IKeyDown {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam);
}

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

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

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

--
  Simen


Re: Call method if declared only

2020-02-28 Thread Виталий Фадеев via Digitalmars-d-learn

On Friday, 28 February 2020 at 08:36:53 UTC, mipri wrote:
On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев 
wrote:

[...]


The pattern throughout Phobos is static tests, like 
isInputRange!R


[...]


It cool !
I will try !
Thank you !


Re: Call method if declared only

2020-02-28 Thread mipri via Digitalmars-d-learn

On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote:

Searching for beauty readable code...


The pattern throughout Phobos is static tests, like isInputRange!R

So something like this:

  import std.stdio;
  import std.traits;

  template canOnKey(T) {
  static if (__traits(hasMember, T, "onKey"))
  enum canOnKey = isCallable!(__traits(getMember, T, 
"onKey"));

  else
  enum canOnKey = false;
  }

  struct A { void onKey() { writeln("called A"); } }
  struct B { }
  struct C { bool onKey = false; }

  void maybeKey(T)(T o) if (canOnKey!T) {
  o.onKey();
  }
  void maybeKey(T)(T o) if (!canOnKey!T) { }

  void main() {
  auto a = A(), b = B(), c = C();
  maybeKey(a);
  maybeKey(b);
  maybeKey(c);
  }

output:

  called A

(and no other output)

Of course in this exact instance it would be simpler to write

  void maybeKey(T)(T o) {
  static if (canOnKey!T)
  o.onKey();
  }

And rather than lots of specific hasThisExactMethod!T tests, it
might be nice if in your actual program there's a 'class' of
grouped properties that you can test for all at once, again
like isInputRange!T and friends.


Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote:
On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев 
wrote:

Searching solution for idea !

Goal is to get System message, dispatch/route to method !
If method implemented only !

I dream on in future write clean code of a derived widgets 
like this :


class Base
{
   // dispatch
   void On( message ... )
   {
   // call On()
   // example: call OnKeyUp() - if method OnKeyUp() is 
exists only

   }
}

May be other than derived ? May be templating ?
How to implement ?


Now I go in ths way:

[snip]

Searching for beauty readable code...


Here's an attempt. It looks up all subclasses of Base in the same 
module, and calls the named method if it exists. However, it will 
fail for any subclass of Base that is defined in a different 
module.


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

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
default:
}
return 0;
}

auto tryCall(string name, Args...)(Args args) {
import std.meta;

alias This = typeof(this);
alias module_ = __traits(parent, This);

enum isSubclass(T...) = is(T[0] : This);
alias getModuleMember(string name) = __traits(getMember, 
module_, name);

enum hasMethod(T) = __traits(hasMember, T, name);

// Get every member in this module
enum memberNames = __traits(allMembers, module_);
alias members = staticMap!(getModuleMember, memberNames);

// Filter away anything that isn't derived from Base
alias subclasses = Filter!(isSubclass, members);

// Get rid of anything that doesn't have a method with 
the correct name
alias subclassesWithMethod = Filter!(hasMethod, 
subclasses);


// Sort them so you get the most derived types first
alias Types = DerivedToFront!subclassesWithMethod;

// Check for each type if the `this` is an instance of 
that specific one

static foreach (T; Types) {
if (cast(T)this !is null) {
// And look up that method and call it.
return __traits(getMember, cast(T)this, 
name)(args);

}
}

// If `this` is not one of the types with that method, 
return some default value

return 0;
}
}

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

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

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

--
  Simen


Re: Call method if declared only

2020-02-28 Thread Виталий Фадеев via Digitalmars-d-learn

On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:

Searching solution for idea !

Goal is to get System message, dispatch/route to method !
If method implemented only !

I dream on in future write clean code of a derived widgets like 
this :


class Base
{
   // dispatch
   void On( message ... )
   {
   // call On()
   // example: call OnKeyUp() - if method OnKeyUp() is 
exists only

   }
}

class Derived : Base
{
   // method implementation
   void OnKeyUp( ... )
   {
   //
   }
}



I tryed code like this:

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


class Base
{
   LRESULT On( UINT message, WPARAM wParam, LPARAM lParam )
   {
switch ( message )
{
case WM_KEYDOWN:
OnWM_KEYDOWN( wParam, lParam );
 //   <-- but it required declared OnWM_KEYDOWN(...) in base 
class Base. How will be without declaring in Base ?

break;

default:
}
   }
}


class Button : Base
{
LRESULT OnWM_KEYDOWN( WPARAM wParam, LPARAM lParam )
{
writeln( "WM_KEYDOWN" );
}
}


May be other than derived ? May be templating ?
How to implement ?


Now I go in ths way:

import std.stdio;
import std.traits;


class Base
{
void On( alias THIS )( int message )
{
static if (
   __traits( hasMember, THIS, "OnKey" ) &&
   isCallable!( __traits( getMember, THIS, 
"OnKey" ) )

  )
{
__traits( getMember, THIS, "OnKey" )();
}
}

void run( alias THIS )()
{
On!THIS( 1 );
}
}

class A : Base
{
void OnKey()
{
writeln( "A.OnKey()" );
}
}


void main()
{
auto a = new A();
a.run!a();
}


Searching for beauty readable code...