Fullscreen
Loading...
 

WM_TUTORIAL_HELLOWORLD

Hello XPlane

Version: 0.5.0
Date: June 1st, 2015

 

Introduction

When we started programming we most likely began with the infamous Hello World and this tutorial won't be any different.  The purpose for this tutorial is to introduce you to the basic components of the PluginApplication class which is the heart of every Wingman plugin.

These tutorials are meant to be quick and to the point.  If you have any issues or questions please go to the Forum and ask there.

Background

The Wingman Framework includes a template called "myplugin", and this is a starting point for this tutorial and for any plugin project you start.

Also this tutorial is for a non-aircraft plugin, meaning it will load no matter what aircraft you have selected.

Finally, this tutorial uses MS-Windows file paths but if you are a Linux user you will get the gist of what is going on.

Assumptions:

  • You've read the Getting Started Guide
  • Have your development environment setup, IDE etc
  • Have ClamShell Compiler running
  • Have WingmanOSS plugin installed

If you don't have the above then you need to read the Getting Started Guide

 

Setup and Compile

Step 1. Start XPlane

Step 2: Copy the template to a new plugin location

Copy C:\Program Files\XPlane\Resources\Wingman\sample\myplugin and copy it to C:\Program Files\XPlane\Resources\plugins

Step 3: Start ClamShell and login 

User ID = 'user'

Password = 'password'

Step 4: Change directory to the template.

cd /media/sf_xplane/Resources/plugins/myplugin

Step 5: Compile

If you are running Windows 64 bit then type:

make OS=WIN64 DEBUG=ON

or for Windows 32 type:

make OS=WIN32 DEBUG=ON

Run

In XPlane select from the main menubar "Plugin->WingmanOSS->Restart Plugins"

Select "Understood" in the window.

Now if you go back to the Plugins menu you'll see a new option called "myplugin", now click on the "Hello World" menu item.

You'll get a window pop up with the title "Hello World" and a "Okay" button. Click the "Okay" button to hide the window.

Wow that was simple!
 

Understanding the Code


myplugin.h

The header file is contains the class definition.

MyPlugin Header
#include "wingman.h"

using namespace wingman;

class Myplugin  : public wingman::PluginApplication
{
public:
    virtual void Initialize();
    virtual void Disable();
    virtual bool Start();
    virtual bool Stop();

private:
    void menu_about_cb(MenuItemObject &menu);
    void menu_hello_cb(MenuItemObject &menu);
    void okay_clicked(XPPushButton &widget);

    XPWindow *hello_window;
};

 
Line 1: To make life simple, all you need to do is include this header file. This is a catch all header that includes all the Wingman Framework header files. You don't have to know or remember which header file to include for what class. Simply add this and you are good to go.

Line 3: Wingman is placed under the "wingman" namespace so instead of you putting "wingman::" in front of every single class, object etc... just add this to the top of your header file and you are good to go.

Line 5: This is the class definition. As you can see she inherits the PluginApplication class.

Line 8-11: You need each one of these methods as they are the basic interface to XPlane.

  • Intialize() - Called right when your plugin is loaded. Create your objects here
  • Start() - Called after Initialize(), this is where you would start events to your plugin.
  • Disable() - Called when XPlane wants to stop your plugin
  • Stop() - Called when XPlane unloads your plugin.


myplugin.cpp

The CPP file, or C-Plus-Plus, is the implementation part of your plugin class.

 

MyPlugin Source - Main
PluginApplication &PluginApplication::main()
{
    static PluginApplication *app;

    if (app == NULL)
    {
        app = new Myplugin();
        app->SetName("Myplugin", PLUGIN_VERSION);
        app->SetSignature("myplugin.applet");
        app->SetDescription("Hello world plugin");
    }

    return(*app);
}


Consider the above code the main(). Wait, it is called main() but its a little different then the "int main(int argc, char argv[][]) we are used to. 

This is where you instantiate your plugin's class, called "MyPlugin" and return the a reference of it. After you've created the object, you need to give the plugin its name, signature and the description of the plugin.

Line 3: You might be asking what this is and its nothing more then a singleton pattern. We only want one, never more, then one instance of your plugin class created and hence the reason it has "static" in front of it.


 

MyPlugin Initialize - Main
void Myplugin::Initialize()
{
    /*Create objects here */
    MenuItem *item = NULL;

    this->CreateSystemMenu("MyPlugin");
    item = new MenuItem("Hello");
    AddSystemMenuItem(*item);
    item->SetSelectEventHandler( MENU_SELECT_EVENT(&Myplugin::menu_hello_cb, this) );

    item = new MenuItem("About");
    AddSystemMenuItem(*item);
    item->SetSelectEventHandler( MENU_SELECT_EVENT(&Myplugin::menu_about_cb, this) );

    this->SetAboutBoxInfo(
        "myPlugin",
        "Hello World",
        "By: A rose by any other name"
    );

    hello_window = new XPWindow("winHelloWorld", "Hello World");
    hello_window->SetSize(300, 300);
    hello_window->SetLocation(50, 100);

    wingman::XPPushButton *button = new XPPushButton("btnOk", "Okay");
    hello_window->AddChild(*button);
    button->SetSize(100, 20);
    button->SetLocation(100, 250);
    button->SetClickEventHandler(XPBUTTON_CLICK_EVENT(&Myplugin::okay_clicked, this));
    button->Show();

    LOG_INFO << "Example of INFO" << WM_ENDL;
    LOG_WARN << "Example of WARNING" << WM_ENDL;
    LOG_ERROR << "Exmaple of ERROR" << WM_ENDL;
    LOG_FATAL << "Example of FATAL" << WM_ENDL;
    DEBUG_1 << "Example of DEBUG LEVEL 1" << WM_ENDL;
    DEBUG_2 << "Example of DEBUG LEVEL 2" << WM_ENDL;
    DEBUG_3 << "Example of DEBUG LEVEL 3" << WM_ENDL;
    DEBUG_4 << "Example of DEBUG LEVEL 4" << WM_ENDL;
}

If you've ever done a little bit of GUI coding the above is pretty straight forward on instansiating and setting properties of an object.

Lines 32 -39 : You maybe asking where are these being written to. The answer is in the XPlane log. Open up  C:\Program Files\XPlane\Log.txt

NOTE: You probably won't see the DEBUG lines because you need to set the debug verbose level. This is done by updating the wingman.ini file that was just creating in the myplugin directory.

 

Set debug verbose
[DEBUG]
# ****************************************************************************
# verbose=[0-4]
# Description: Level of detail to set the debug output too.
# ----------------------------------------------------------------------------
# 0 = OFF
# 1 =
# 2 =
# 3 =
# 4 = FULL
# ****************************************************************************
verbose=0

To enable debug ouput, open the wingman.ini file with either Notepad or WordPad and find the section listed above and change "verbose=0" to "verbose=4"

Restart the plugin WingmanOSS->Restart Plugins and click "Understood".

Open up XPlanes Log.txt file and you should now see the debug output.

 

MyPlugin Source - Start/Stop & Disable
bool Myplugin::Start()
{
    bool retval = false;
    /* Start events here */
    retval = true;
    return(retval);
}

bool Myplugin::Stop()
{
    bool retval = false;
    /* Unallocate memory/objects here */
    retval = true;
    return(retval);
}

void Myplugin::Disable()
{
    /* Stop Events Here */
}


The above methods are bundled together because they don't do anything right now, they simply return true which basically they are saying, "Yup' i'm happy".

When your plugin gets more complicated then these methods will fill up with your code.

 

MyPlugin Source - Callback handlers
void Myplugin::menu_about_cb(MenuItemObject &menu)
{
    ShowAboutBox();
}

void Myplugin::menu_hello_cb(MenuItemObject &menu)
{
    hello_window->Show();
}

void Myplugin::okay_clicked(XPPushButton &widget)
{
    hello_window->Hide();
}


The above methods are the callback handlers for the menu items as well as the okay button when click in the Hello World dialog.