AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
7GUIs Flight Booker

Note
This page describes an example listed in 7GUIs.
Flight Booker.

Challenge: Constraints.

The task is to build a frame containing a combobox C with the two options “one-way flight” and “return flight”, two textfields T1 and T2 representing the start and return date, respectively, and a button B for submitting the selected flight. T2 is enabled iff C’s value is “return flight”. When C has the value “return flight” and T2’s date is strictly before T1’s then B is disabled. When a non-disabled textfield T has an ill-formatted date then T is colored red and B is disabled. When clicking B a message is displayed informing the user of his selection (e.g. “You have booked a one-way flight on 04.04.2014.”). Initially, C has the value “one-way flight” and T1 as well as T2 have the same (arbitrary) date (it is implied that T2 is disabled).

The focus of Flight Booker lies on modelling constraints between widgets on the one hand and modelling constraints within a widget on the other hand. Such constraints are very common in everyday interactions with GUI applications. A good solution for Flight Booker will make the constraints clear, succinct and explicit in the source code and not hidden behind a lot of scaffolding.

/*
* AUI Framework - Declarative UI toolkit for modern C++20
* Copyright (C) 2020-2024 Alex2772 and Contributors
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <ctre.hpp>
#include <AUI/Platform/Entry.h>
#include <AUI/Platform/AWindow.h>
#include <AUI/Util/UIBuildingHelpers.h>
#include "AUI/View/ADropdownList.h"
#include "AUI/Model/AListModel.h"
#include "AUI/View/ATextField.h"
#include "AUI/Platform/AMessageBox.h"
using namespace declarative;
using namespace std::chrono;
constexpr auto REGEX_DATE = ctre::match<"([0-9]+)\\.([0-9]+)\\.([0-9]{4})">;
struct DateTextFieldState {
};
auto formatDate(system_clock::time_point date) {
    return "{0:%d}.{0:%m}.{0:%G}"_format(date);
}
auto dateTextField(DateTextFieldState& state) {
    return _new<ATextField>() let {
        AObject::biConnect(
            state.parsed.biProjected(aui::lambda_overloaded {
              [](const AOptional<system_clock::time_point>& v) -> AString {
                  if (!v) {
                      return "";
                  }
                  return formatDate(*v);
              },
              [](const AString& s) -> AOptional<system_clock::time_point> {
                  auto std = s.toStdString();
                  auto match = REGEX_DATE.match(std);
                  if (!match) {
                      return std::nullopt;
                  }
                  return sys_days(year_month_day(
                      year(std::stoi(match.get<3>().str())), month(std::stoi(match.get<2>().str())),
                      day(std::stoi(match.get<1>().str()))));
              },
            }),
            it->text());
        it & state.parsed > [](AView& textField, const AOptional<system_clock::time_point>& value) {
            textField.setAssName(".red", !value.hasValue());
        };
    };
}
class FlightBookerWindow : public AWindow {
public:
    FlightBookerWindow() : AWindow("AUI - 7GUIs - Book Flight", 150_dp, 50_dp) {
        setExtraStylesheet(AStylesheet { {
          ass::c(".red"),
          ass::BackgroundSolid { AColor::RED },
        } });
        setContents(Centered {
          Vertical {
            _new<ADropdownList>(AListModel<AString>::make({ "one-way flight", "return flight" })) let {
                    connect(it->selectionId().readProjected([](int selectionId) { return selectionId == 1; }),
                            mIsReturnFlight);
                },
            dateTextField(mDepartureDate),
            dateTextField(mReturnDate) let { connect(mIsReturnFlight, slot(it)::setEnabled); },
            _new<AButton>("Book") let {
                    connect(it->clicked, me::book);
                    connect(mIsValid, slot(it)::setEnabled);
                },
          },
        });
    }
private:
    DateTextFieldState mDepartureDate { system_clock::now() }, mReturnDate { system_clock::now() };
    AProperty<bool> mIsReturnFlight;
    APropertyPrecomputed<bool> mIsValid = [&] {
        if (!mDepartureDate.parsed->hasValue()) {
            return false;
        }
        if (!mIsReturnFlight) {
            return true;
        }
        if (!mReturnDate.parsed->hasValue()) {
            return false;
        }
        if (mDepartureDate.parsed->value() > mReturnDate.parsed->value()) {
            return false;
        }
        return true;
    };
    void book() {
        AString msg = "Departure - {}"_format(formatDate(mDepartureDate.parsed->value()));
        if (mIsReturnFlight) {
            msg += "\nReturn - {}"_format(formatDate(mReturnDate.parsed->value()));
        }
        AMessageBox::show(this, "You've booked the flight", msg);
    }
};
    _new<FlightBookerWindow>()->show();
    return 0;
}
static _< AListModel< StoredType > > make(const std::initializer_list< V > &t)
Definition AListModel.h:251
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition AOptional.h:33
Represents a Unicode character string.
Definition AString.h:38
void setContents(const _< AViewContainer > &container)
Moves (like via std::move) all children and layout of the specified container to this container.
Base class of all UI objects.
Definition AView.h:78
void setExtraStylesheet(_< AStylesheet > extraStylesheet)
Definition AView.h:238
void setAssName(const AString &assName, bool value)
Depending on value, either adds or removes ass name.
Definition AView.h:697
Represents a window in the underlying windowing system.
Definition AWindow.h:45
class_of c
Selects views that are of the specified classes.
Definition class_of.h:84
static void biConnect(PropertySource &&propertySource, PropertyDestination &&propertyDestination)
Connects source property to the destination property and opposite (bidirectionally).
Definition AObject.h:156
static decltype(auto) connect(const Signal &signal, Object *object, Function &&function)
Connects signal to the slot of the specified object.
Definition AObject.h:86
#define slot(v)
Passes some variable and type of the variable separated by comma. It's convenient to use with the con...
Definition kAUI.h:88
#define let
Performs multiple operations on a single object without repeating its name (in place) This function c...
Definition kAUI.h:262
#define AUI_ENTRY
Application entry point.
Definition Entry.h:90
API_AUI_VIEWS ResultButton show(AWindow *parent, const AString &title, const AString &message, Icon icon=Icon::NONE, Button b=Button::OK)
Displays a message box, blocking the caller thread until the user dismisses the message.
Basic easy-to-use property implementation containing T.
Definition AProperty.h:30
Definition callables.h:36

Regex Library#

For validation in this example, we've chosen using regex technology, as it's fairly simple and extensible way to make parsers.

Despite STL provides regex implementation, it varies from compiler to compiler, compiles the regex expression at runtime only, and some platforms may even lack builtin regex library. To avoid possible issues, custom implementation should be used.

Although AUI does not provide a regex parser on its own, nothing stops you from using AUI.Boot in order to pull awesome 3rdparty implementation of your choice that suits your exact needs. For this example, we've chosen ctre, as it evaluates the regex expression at compile-time, emitting effective code, as if we were validating the string manually.

cmake_minimum_required(VERSION 3.10)
auib_import(ctre https://github.com/hanickadot/compile-time-regular-expressions
            VERSION v3.9.0)
aui_executable(aui.example.flight_booker)
aui_link(aui.example.flight_booker PRIVATE aui::views ctre::ctre)

Source Files#