MX2 for Desktop Application Programming

Community Forums/Monkey2 Talk/MX2 for Desktop Application Programming

Danilo(Posted 2016) [#1]
Made a small (native) GUI test today to see how MX2 could be used for application programming:




' Import Frameworks
#Import "<AppKit.monkey2>"

Using AppKit
Using AppKit.Gui

Function Main()
    Local app := New Application()
    
    Local win1 := New Window(50,100,300,200,"MonkeyX2 AppKit.Gui Demo")
    Local win2 := New Window(360,100,300,200,"Window 2")
    Local win3 := New Window(670,100,320,200,"Window 3")
    
    Local btn1 := New Button(10,10,100,25,"Button 1")
    Local btn2 := New Button(10,45,100,25,"Button 2")
    Local chk1 := New Checkbox(10,80,100,25,"Checkbox")

    btn1.Clicked = Lambda()
                       Print("Button 1 Clicked!")
                   End
    
    btn2.Clicked = Lambda()
                       Print("Button 2 Clicked!")
                   End

    chk1.Clicked = Lambda()
                       Print("Checkbox Clicked!")
                   End
    
    win1.AddWidget( btn1 )
    win1.AddWidget( btn2 )
    win1.AddWidget( chk1 )

    Local quitBtn  := New Button(10,10,100,25,"Quit")
    quitBtn.Clicked = Lambda()
                          Print("quitBtn Clicked!")
                          app.Quit()
                      End

    Local progress := New Progressbar(10,50,280,25,0,100)
    progress.SetValue(50)

    Local plusBtn  := New Button(50,80,35,35,"+")
    plusBtn.Clicked = Lambda()
                          progress.SetValue( progress.GetValue() + 1.0 )
                      End

    Local minusBtn := New Button(10,80,35,35,"-")
    minusBtn.Clicked = Lambda()
                          progress.SetValue( progress.GetValue() - 1.0 )
                       End

    Local slider  := New Slider(10,130,280,25)
    slider.Changed = Lambda()
                         Print("Slider changed: "+slider.GetValue())
                         progress.SetValue( slider.GetValue() )
                     End

    slider.SetValue(50)

    win2.AddWidget( quitBtn )
    win2.AddWidget( progress )
    win2.AddWidget( plusBtn)
    win2.AddWidget( minusBtn)
    win2.AddWidget( slider )

    Local sliders:Slider[] = New Slider[10]
    
    For Local i := 0 To 9
        sliders[i] = New Slider(10+i*30,10,25,180)
        sliders[i].SetValue( i * 10 )
        win3.AddWidget( sliders[i] )
    Next
    
    app.Run()
End


Looking forward to the next demo... :)


GC-Martijn(Posted 2016) [#2]
that + and - are not good aligned ;)


Playniax(Posted 2016) [#3]
Yep, Monkey 2 looks promissing!


Danilo(Posted 2016) [#4]
Actually, writing own libs/frameworks seems to be easier (in my opinion) than importing foreign 3rd-party C++ codes,
because external stuff often uses 'Type&'-references etc. --- and not all C++ features can be translated 1:1 to MX2.


Playniax(Posted 2016) [#5]
Phew, I am still in business then... :)


taumel(Posted 2016) [#6]
*looking at the code*
I expect monkey2 to be fun, contrary to Monkey.

If only the syntax could be easier, less, more modern, discrete ...

Too many shifted characters/lambdas/ends for my taste, it looks like it's trying to look pro but lacks a lightweight/fun-feeling.

Regarding the functionality i hope it will be a complete (without Monkey like holes) but RISC like focused approach.

Also looking forward to the next demo. Look, a Soyuz starting from an island crater into 3d space.


Danilo(Posted 2016) [#7]
Another thing is the great MX2 build-system. The Framework (AppKit) needs to be compiled one time only (at Install),
and end-user codes like above start almost instantly (half a second), even after changes. Really great! I am very happy!


Neuro(Posted 2016) [#8]
And no OpenAl32.dll required?? Cool!!!


Richard Betson(Posted 2016) [#9]
Actually, writing own libs/frameworks seems to be easier (in my opinion)

I would say that doing it native style allows a richer, nicer and friendlier framework. ;) I know that is my experience in coding my own framework.


degac(Posted 2016) [#10]
Very nice!
I start to love the lambda thing!
Mx2 seems on the right road...


Richard Betson(Posted 2016) [#11]
I start to love the lambda thing!

It is nice but I am not sure I will personally use it all the time. For example even though I am writing a GUI framework I would personally prefer using a 'Select' statement to scan GUI component ID's (whats clicked). You would think a GUI is a natural for the above Lambda style and it is, I just prefer a different style. One other thing to consider is portability between other BRL products.

For those looking at Lambdas it is not necessary (but very useful) to use them.


degac(Posted 2016) [#12]
@Lambda & GUI
Of course Lambda() doesn't mean you must use it everywhere.
But one thing is quite clear: less IF..THEN /SELECT etc
The possibility to assign a 'default' job/behaviour (like change the text value when clicking on +/-) AND using the 'old' approach (SELECT.. IF/THEN etc) opens a new level of GUI-messages management.
Look at the slider: you move the knob and somewhere you see changing the progress-bar value. There's a 'colorslider' somewhere for BMAX/MaxGUI (a proxygadget from JoshK I think). to manage everything there's plenty of Select/If etc. Here 2 lines of code. Handy!)


Danilo(Posted 2016) [#13]
It's not required to use Lambda(), we can also use Methods for event handling.
' Import Frameworks
#Import "<AppKit.monkey2>"

Using AppKit
Using AppKit.Gui

Class myApp Extends Application
    Field mainWindow:Window
    Field quitButton:Button

    Method New()
        mainWindow = New Window(50,100,300,200,"Window")
        quitButton = New Button(10, 10,100, 25,"Quit")

        quitButton.Clicked = QuitButtonClicked
        
        mainWindow.AddWidget( quitButton )
        
        Self.Run()
    End
    
    Method QuitButtonClicked()
        Self.Quit()
    End
End

Function Main()
    New myApp
End



rIKmAN(Posted 2016) [#14]
Would anyone be willing to write a tutorial or set of guides of how to go about using external libraries in MX2, externs, the glue code, any gotchas and things to watch for etc etc?

I think it would really help the community fill in any gaps and to extend MX2, but there doesn't seem to be much information on how to go about it if you don't already know what you doing and understand the whole process. I know you can look at others code and learn, but there are always questions and parts that aren't really understood.

I would love to write some myself (for Monkey1 as well) but could never get my head around it for some reason, and I assume I'm not the only one? (Hope not anyway!)

@Danilo: You're doing some great things with MX2, keep it up! :)


Richard Betson(Posted 2016) [#15]
Of course Lambda() doesn't mean you must use it everywhere.
But one thing is quite clear: less IF..THEN /SELECT etc

My point I guess is Lambdas are cool and code savers and everyone should exploit them fully, but they are only another convenience. Personally after porting code (my current project) from BlitzMax to Monkey-X1 and soon to Monkey-X2 I can say that keeping things focused on basics of the syntax/language (types, methods, function and so on) yields portable code, well beyond BRL products. When coding using language specific features porting code becomes much harder. I like to use the most basic language syntax and "port friendly" parts of a language. In the case of my current project I was able to convert code from BlitzMax to Monkey-X1 with relative ease only because I used this approach. For many though use of lambdas is not a problem and I would think in many instances preferable especially coming over from C/C++.

As Danilo's example's show there are several ways to reach your goal be that lambdas or good old methods or whatever. ;)


impixi(Posted 2016) [#16]
@riKmAN:

Would anyone be willing to write a tutorial or set of guides of how to go about using external libraries in MX2, externs, the glue code, any gotchas and things to watch for etc etc?


I think it's too early for this yet. There's a lot in MX2 not yet finalized, so any tutorials and documentation would be out of date as soon as it were written...


rIKmAN(Posted 2016) [#17]
@impixi:
I think it's too early for this yet. There's a lot in MX2 not yet finalized, so any tutorials and documentation would be out of date as soon as it were written...


Yeah I completely agree, but I just wanted to put it out there early as it was something which is/was lacking in Monkey1 and ended up with only a select bunch of (very talented) devs who could/would be able to write modules. Is there even a single guide/tutorial or any help at all for this in Monkey1? That's my point.

If there were (un)official forums/guides/tutorials or whatever specifically aimed at helping people learn how to wrap modules in MX2 it would allow the community to fill in any gaps and spread the weight between as many people as were interested, as opposed to just Mark and the aforementioned devs who already know what they are doing.

How similar is wrapping in MX2 when compared to Monkey?
Danilo seems to be flying along and every time he posts it's something exciting - imagine if there were 5/10/20 people doing the same thing!

PS. I should say - if I have completely missed anything on this forum which does what i am saying, or if there is any external reading which could help me learn and understand the process then please point me to it! :)


Leo Santos(Posted 2016) [#18]
Quick question: what kind of field is, for instance, quitButton.Clicked? Is it a method or property?

I see that you're assigning a function to it, and that function gets called when the button is clicked, which is really cool, but I can't understand what kind of field (or method) ".Clicked" is. How does that work, exactly?

Thanks!


Danilo(Posted 2016) [#19]
It’s a 'function variable‘ -> a variable that holds a reference/connection to, and can call, functions/methods/lambdas.
'
' Function Variables in MX2
'
Function Main()
    New Program
End

Class Program

    Method New()
        Local func:Void(x:Int) ' declare a function variable 'func'
                               ' that can call functions/methods/lambdas
                               ' with signature Void(x:Int)
        Print("----------")
        
        func(0)                ' call it - nothing happens because
                               ' nothing was assigned to it before
        Print("----------")
        
        func = methodA         ' assign a method
        
        func(1)                ' call it - it runs methodA
 
        Print("----------")

        func = methodB         ' assign another method
        
        func(2)                ' call it - it runs methodB

        Print("----------")

        func = Lambda:Void(x:Int) ' assign a lambda
            Print("lambda: x = "+x)
        End
        
        func(3)                ' call it - it runs the lambda

        Print("----------")
        
        func += methodB        ' add methodB
        func += methodA        ' add methodA

        func(4)                ' call it - it runs now all 3:
                               ' lambda, methodB, methodA
    End
    
    Method methodA:Void(x:Int)
        Print("methodA: x = "+x)
    End

    Method methodB:Void(x:Int)
        Print("methodB: x = "+x)
    End
End



Leo Santos(Posted 2016) [#20]
Excellent, thanks for taking the time to clarify it! This seems incredibly useful.

Just out of curiosity, is "Clicked" a function variable natively in AppKit, or is that something you wrapped in AppKit.monkey2 to make it easier to use?
Thanks!!


wiebow(Posted 2016) [#21]
Clicked is a Function in the Button class.


k.o.g.(Posted 2016) [#22]
@Danilo

I can't test it now, but i hope that this:
        Local func:Void(x:Int) ' declare a function variable 'func'
                               ' that can call functions/methods/lambdas
                               ' with signature Void(x:Int)
        Print("----------")
        
        func(0)                ' call it - nothing happens because
                               ' nothing was assigned to it before
        Print("----------")


gives an exception? (null pointer)
was it only pseudocode?


Danilo(Posted 2016) [#23]
@Leo Santos / wiebow:
It’s an external "function variable":
Extern

    Class Button Extends WidgetBase = "AppKit::Gui::Button"
        Field Clicked:Void()="clicked"
        
        Method New()
        Method New(x:Int, y:Int, width:Int, height:Int, title:String)
    End

My external C++ class is defined as:
#include <bbmonkey.h>

namespace AppKit {
    namespace Gui {
        class Button : public WidgetBase {
            public:
            bbFunction<void()> clicked;

            Button();
            Button(int x, int y, int width, int height, bbString text);
        };

To execute the function variable in C++ (call the MX2 method/lambda), you just use the operator () in C++:
this->clicked()


@k.o.g.:
Real, run-able MX2 code. No exception, it just does nothing. A function variable is not just a function pointer,
it’s a more complex type (template class in C++) that holds references/connection to several types (functions/methods/lamdas).
Calling/Using a function variable uses the overloaded operator () to execute all registered „callbacks“ sequencially (as shown in my example).
If nothing was registered, it just does nothing. No exception thrown.


julesd(Posted 2016) [#24]
Just wondering, is it possible to overlay your GUI over 3D graphics.
Perhaps the Vortex module.


Danilo(Posted 2016) [#25]
@julesd:
I don't think so, because it is native GUI provided by the platform (Mac, Win).


rebelas(Posted 2016) [#26]
For apps we need database connection, in my case, I need for sqlite.