NoesisGUI

Application Framework

github Tutorial Data

ApplicationTutorialImg1.jpg

Although noesisGUI can be fully integrated within your application, as shown in the integration tutorial, an Application Framework is also provided. This framework is an open source library that provides abstractions to create multiplatform applications. The framework is a good example about how to use Noesis and it provides many helpers that can be useful. All our samples use the application framework.

The extensions provided, like Application and Window, are compatible with WPF, so compatible with Microsoft Blend. Using the application framework you can design applications that will indistinctly run in a Windows window, macOS window, iPhone screen, or Xbox TV for example. The framework supports all the platforms where NoesisGUI is available.

spacer.png

Headers and Namespace

Headers for the application framework are contained within the NsApp and NsRender modules. The API is exposed in the NoesisApp namespace.

#include <NsApp/EntryPoint.h>
#include <NsApp/Application.h>
#include <NsApp/ApplicationLauncher.h>
#include <NsApp/Window.h>
#include <NsApp/EmbeddedXamlProvider.h>
#include <NsApp/EmbeddedFontProvider.h>

using namespace Noesis;
using namespace NoesisApp;

NOTE

Note how framework headers are not inside standard NoesisGUI include folder neither part of 'Noesis_pch.h' precompiled header.

Entry Point

As main() is not available in all platforms, the framework provides a portable entrypoint, NsMain. You will normally create here a Launcher, configure it and Run() it.

int NsMain(int argc, char **argv)
{
    AppLauncher launcher;
    launcher.SetArguments(argc, argv);
    launcher.SetApplicationFile("App.xaml");
    return launcher.Run();
}

Launcher

The Launcher is the first instance you create. It is in charge of application initialization and main message loop. It also provides a few important overridable functions:

  • RegisterComponents: for registering classes in the component factory. Each extended class that need to be instantiated by XAML needs to be registered here as explained in the Extending NoesisGUI tutorial. For the framework you need to register at least the Application and Window class.
  • GetXamlProvider, GetFontProvider and GetTextureProvider: for customizing how resources are loaded. You can install custom handlers for XAMLs, font and textures as explained in the Customizing Resource Loading tutorial.
class AppLauncher final: public ApplicationLauncher
{
private:
    void RegisterComponents() const override
    {
        NsRegisterComponent<RssReader::App>();
        NsRegisterComponent<RssReader::MainWindow>();
    }

    Ptr<XamlProvider> GetXamlProvider() const override
    {
        EmbeddedXaml xamls[] =
        {
            { "App.xaml", App_xaml, sizeof(App_xaml) },
            { "MainWindow.xaml", MainWindow_xaml, sizeof(MainWindow_xaml) }
        };

        return *new EmbeddedXamlProvider(xamls, NS_COUNTOF(xamls));
    }

    Ptr<FontProvider> GetFontProvider() const override
    {
        EmbeddedFont fonts[] =
        {
            { "", Roboto_Regular_ttf, sizeof(Roboto_Regular_ttf) },
            { "", Roboto_Bold_ttf, sizeof(Roboto_Bold_ttf) }
        };

        return *new EmbeddedFontProvider(fonts, NS_COUNTOF(fonts));
    }
};

NOTE

The Embedded* family of resource providers found in the framework allows you to embed resources in the executable. Each time you edit a resource contained in the project it is automatically converted to a header file using 'bin2h', an internal tool. For example, 'Roboto-Regular.ttf.bin.h' is automatically regenerated each time you touch ''Roboto-Regular.ttf'. The same for the rest of resources.

Application

The application class directly correspond to the WPF Application Class. Each application provides its own implementation inheriting from Application base class.

namespace RssReader
{
    class App final: public Application
    {
        NS_IMPLEMENT_INLINE_REFLECTION(App, Application)
        {
            NsMeta<TypeId>("RssReader.App");
        }
    };
}

The main purpose of the Application is providing a global resource dictionary and setting the main window, the StartupUri.

App.xaml
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             x:Class="RssReader.App">

  <Application.Resources>
    <SolidColorBrush x:Key="Background0" Color="#FF2F3F4F" />
    <SolidColorBrush x:Key="Background1" Color="SlateGray" />
    <SolidColorBrush x:Key="Foreground0" Color="White" />
    <SolidColorBrush x:Key="Foreground1" Color="SkyBlue" />
    <SolidColorBrush x:Key="Foreground2" Color="Black" />
    <SolidColorBrush x:Key="Border" Color="LightSlateGray" />
    <FontFamily x:Key="DefaultFont">./#Roboto</FontFamily>
  </Application.Resources>

</Application>

Window

The Window class mimics the WPF Window Class. It is a container that shows its content inside an operating system window. Public properties like Title, ResizeMode, WindowStyle, Width and Height control the aspect of the native window.

MainWindow.xaml
<Window
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="NoesisGUI - RSS Reader" Width="487" Height="630" ResizeMode="NoResize"
   Background="{StaticResource Background0}"
   Foreground="{StaticResource Foreground0}"
   FontFamily="{StaticResource DefaultFont}"
   x:Class="RssReader.MainWindow">

  <Viewbox>
    <DockPanel Background="{StaticResource Background0}" LastChildFill="True"
               KeyboardNavigation.TabNavigation="Contained"
               KeyboardNavigation.DirectionalNavigation="Contained" Width="325" Height="420">
      <TextBlock DockPanel.Dock="Top" Text="RSS Reader" FontSize="32" FontWeight="Bold"
                 TextAlignment="Center" Margin="0,10,0,0"/>
      <Border DockPanel.Dock="Top" Background="{StaticResource Background1}"
              BorderBrush="{StaticResource Border}" BorderThickness="1" CornerRadius="2"
              Margin="10" Padding="15,5">
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
          </Grid.ColumnDefinitions>
          <TextBlock Grid.Column="0" Text="URL: " VerticalAlignment="Center"/>
          <TextBox x:Name="Address" Grid.Column="1" Text="http://www.metacritic.com/"/>
          <Button x:Name="GoTo" Grid.Column="2" Content="Go" Click="OnGoToClicked" Margin="2,0,0,0"/>
        </Grid>
      </Border>
      <Grid DockPanel.Dock="Bottom" Margin="10">
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.Resources>
          <Style TargetType="Button">
            <Setter Property="BorderBrush" Value="{StaticResource Background1}"/>
          </Style>
        </Grid.Resources>
        <Button x:Name="Prev" Grid.Column="0" Content="Prev" Click="OnPrevClicked"/>
        <Button x:Name="Next" Grid.Column="1" Content="Next" Click="OnNextClicked"/>
      </Grid>
      <Border Background="{StaticResource Background1}" BorderBrush="{StaticResource Border}"
              BorderThickness="1" CornerRadius="2" Margin="10,0" Padding="5">
        <Grid x:Name="ContentPanel" Margin="10,0">
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
          </Grid.RowDefinitions>
          <TextBlock x:Name="EntryTitle" Grid.Row="0" FontSize="20" FontWeight="Bold"
                     Foreground="{StaticResource Foreground1}" TextAlignment="Center" Margin="0,5,0,5"/>
          <ScrollViewer Grid.Row="1"  Margin="0,10" Focusable="False"
                        HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
            <TextBlock x:Name="EntryDesc" TextWrapping="Wrap" Margin="10,0"
                       Foreground="{StaticResource Foreground2}" FontSize="14"/>
          </ScrollViewer>
        </Grid>
      </Border>
    </DockPanel>
  </Viewbox>

</Window>

Window base class is normally extended to implement code-behind functionality.

namespace RssReader
{
    class MainWindow final: public Window
    {
    public:
        MainWindow(): _index(0)
        {
            InitializeComponent();

            _title = FindName<TextBlock>("EntryTitle");
            _desc = FindName<TextBlock>("EntryDesc");
            _title->SetText(gTitles[0]);
            _desc->SetText(gBodies[0]);
        }

    private:
        void InitializeComponent()
        {
            Noesis::GUI::LoadComponent(this, "MainWindow.xaml");
        }

        bool ConnectEvent(BaseComponent* source, const char* event, const char* handler) override
        {
            NS_CONNECT_EVENT(Button, Click, OnGoToClicked);
            NS_CONNECT_EVENT(Button, Click, OnPrevClicked);
            NS_CONNECT_EVENT(Button, Click, OnNextClicked);
            return false;
        }

        void OnGoToClicked(BaseComponent* /*sender*/, const RoutedEventArgs& /*e*/)
        {
        }

        void OnPrevClicked(BaseComponent* /*sender*/, const RoutedEventArgs& /*e*/)
        {
            _index = _index == 0 ? 2 : _index - 1;
            _title->SetText(gTitles[_index]);
            _desc->SetText(gBodies[_index]);
        }

        void OnNextClicked(BaseComponent* /*sender*/, const RoutedEventArgs& /*e*/)
        {
            _index = _index == 2 ? 0 : _index + 1;
            _title->SetText(gTitles[_index]);
            _desc->SetText(gBodies[_index]);
        }

    private:
        int _index;
        TextBlock* _title;
        TextBlock* _desc;

        NS_IMPLEMENT_INLINE_REFLECTION(MainWindow, Window)
        {
            NsMeta<TypeId>("RssReader.MainWindow");
        }
    };
}
© 2017 Noesis Technologies