cross platform VS generator

1 / 4
The main generator screen is similar to cmake except that it only shows user variables.
2 / 4
Its possible to create new variables that can be used in cmake scripts
3 / 4
Its possible to set commands that run after cmake has generated your project
4 / 4
Deployed app has all edit features stripped
1 / 2

        using System.Windows;
using System.Windows.Controls;

namespace cpg
{
  /**
   * @brief Diffent kinds of supported scm systems
   */
  public enum Scm
  {
    Disabled, //!< scm is disabled
    Perforce  //!< Perforce is used for source control management.
  }

  /**
   * @class cpg.ScmSettingsEditor : Window
   * @brief Backend for the Scm settings editor.
   * @author Stan Pepels
   */
  public partial class ScmSettingsEditor : Window
  {
    /**
     * @brief The settings tp be edited.
     */
    public ScmSettings result { get; private set; }

    /**
     * @brief Constructor that uses another setings instance to initialize the resulting settings by copieing the values.
     * @param[in] settings (cpg.ScmSettings) The settings to copy.
     */
    public ScmSettingsEditor(ScmSettings settings)
    {
      if (settings == null)
      {
        Close();
        return;
      }

      InitializeComponent();

      result = new ScmSettings(settings);
      DataContext = result;
    }

    /**
     * @brief Callback for when the Ok button is clicked.
     * @param[in] sender (object) The sender of the event.
     * @param[in] e (RoutedEventArgs) Arguments send with the event
     * @remark Closes the dialog and sets the dialog result to true. 
     */
    private void Ok_Click(object sender, RoutedEventArgs e)
    {
      DialogResult = true;
      Close();
    }

    /**
     * @brief Callback for when the Cancel button is clicked.
     * @param[in] sender (object) The sender of the event.
     * @param[in] e (RoutedEventArgs) Arguments send with the event
     * @remark Closes the dialog and sets the dialog result to false. 
     */
    private void Cancel_Click(object sender, RoutedEventArgs e)
    {
      DialogResult = false;
      Close();
    }

    /**
     * @brief Callback for when the password has changed.
     * @param[in] sender (object) The sender of the event.
     * @param[in] e (RoutedEventArgs) Arguments send with the event
     */
    private void Perforce_PasswordChanged(object sender, RoutedEventArgs e)
    {
      PasswordBox box = sender as PasswordBox;
      if (box != null && box.DataContext == result)
      {
        result.password = box.Password;
      }
    }
  }
}

       
Backend for the scm settings editor
2 / 2

        using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace cpg
{
  /**
   * @class cpg.VariableEditor : Window
   * @brief Back end for the variable editor
   * @author Stan Pepels
   */
  public partial class VariableEditor : Window
  {

    /**
     * @brief the variable with all modifications applied
     */
    public Variable result { get; private set; }

    private Variable base_;                                                   //!< The variable that is being edited.
    private readonly string invalid_chars = "@:\\|&#!*()[] {};'.<>?/$%~-+";   //!< List of chars that are forbidden in the textboxes.
    private readonly VariableList owner_;                                     //!< The owner of the variable we're editing.
    private ulong[] ascii_mask;                                               //!< Mask of invalid ascii characters created from the invalid chars string. used for validation.

    /**
     * @brief Constructor for the editor sets the appropriate datacontext and sets up callbacks
     * @param[in] varaiable (cpg.Variable) Varibale to edit.
     * @param[in] owner (spg.VariableList) The owner of the variable we're editing.
     */
    public VariableEditor(Variable variable, VariableList owner)
    {
      if (variable == null)
      {
        Close();
        return;
      }
      InitializeComponent();

      result = new Variable(variable);
      base_ = variable;
      DataContext = result;

      SetupVariable(variable.type);
      list_editor.OnListItemChanged += List_editor_OnListItemChanged;
      owner_ = owner;
      ascii_mask = new ulong[4];

      for(int i = 0; i < ascii_mask.Length; ++i)
      {
        byte[] invalid_ascii = Encoding.ASCII.GetBytes(invalid_chars);
        foreach(byte ascii in invalid_ascii)
        {
          int index = ascii / 64;
          ascii_mask[index] |= (1u << (ascii % 64));
        }
      }
    }

    /**
     * @brief Callback for when the value of a list item changes
     * @param[in] sender (ListEditor) The list editor that edited the variable
     * @param[in] new_value (string) The new value of the list item.
     * @param[in] old_value (string) The previous value of the list item.
     * @remark This method is only called when the variable is a list.
     */
    private void List_editor_OnListItemChanged(ListEditor sender, string new_value, string old_value)
    {
      if (sender != list_editor)
      {
        return;
      }

      if (result.default_value == old_value)
      {
        result.default_value = new_value;
      }
    }

    /**
     * @brief Sets up a new variable
     * @param[in] type (cpg.VariableTypes) The type of variable to be created.
     */
    private void SetupVariable(VariableTypes type)
    {
      if (list_editor == null)
      {
        return;
      }

      VariableTypes old = result.type;
      result.type = type;

      if (old != result.type)
      {
        switch (old)
        {
          case VariableTypes.List:
            list_editor.SetList(null);
            break;
        }
      }

      switch (result.type)
      {
        case VariableTypes.Bool:
          result.default_value = "false";
          break;
        case VariableTypes.String:
          result.default_value = "";
          break;
        case VariableTypes.List:
            result.container_info = new ObservableCollection<string>();
            result.default_value = "";
          break;
      }


      if (base_.type == result.type)
      {
        result.container_info = base_.container_info;
        result.default_value = base_.default_value;
      }

      list_editor.SetList(result.container_info as ObservableCollection<string>);
    }

    /**
     * @brief Callback for when the type the variable was changed.
     * @param[in] sender (object) The sender of the event.
     * @param[in] e (SelectionChangedEventArgs) Information about how the selection changed.
     */
    private void type_selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      SetupVariable((VariableTypes)Enum.Parse(typeof(VariableTypes), e.AddedItems[0].ToString()));
    }

    /**
     * @brief Callback for when the name of the varable was changed.
     * @param[in] sender (object) The sender of the event.
     * @param[in] e (cpg.TextChangedEventArgs) The new and old value for the name.
     */
    private void name_value_FinalTextChanged(object sender, TextChangedEventArgs e)
    {
      TextBox box = (sender as TextBox);
      if (box == null)
      {
        return;
      }

      if (ValidateString(e.new_text) == false)
      {
        string msg = "Characters: \" ";
        foreach (char c in invalid_chars)
        {
          msg += c;
          msg += " ,";
        }
        box.Text = e.old_text;
        msg += "\"  are not allowed in variable names";
        MessageBox.Show(msg, "Invalid Variable name", MessageBoxButton.OK, MessageBoxImage.Warning);
        return;
      }

      foreach (Variable v in owner_.variables_)
      {
        if (v.name == box.Text)
        {
          box.Text = e.old_text;
          string msg = string.Format("A variable with the name \"{0}\" allready exists.", e.new_text);
          MessageBox.Show(msg, "Variable exists warning", MessageBoxButton.OK, MessageBoxImage.Warning);
          return;
        }
      }
    }

    /**
     * @brief Checks if a string contaains an invalid charcater. Used for validating the name of varibles.
     * @param[in] value (string) The string to be validated.
     * @return (bool) results in true if the string does not contain any invalid characters.
     */
    private bool ValidateString(string value)
    {
      byte[] ascii = Encoding.ASCII.GetBytes(value);
      foreach(byte b in ascii)
      {
        int index = b / 64;
        if ((ascii_mask[index] & (1u << (b % 64))) != 0)
        {
          return false;
        }
      }
      return true;
    }

    /**
     * @brief Callback for when the 'ok' button is pressed. this closes the editor and sets the dialg result to true.
     * @param[in] sender (object) The sender of the event.
     * @param[in] e (RoutedEventArgs) Arguments send with the event
     */
    private void OkButton_Click(object sender, RoutedEventArgs e)
    {
      DialogResult = true;
      Close();
    }

   /**
    * @brief Callback for when the 'cancel' button is pressed. this closes the editor and sets the dialg result to false.
    * @param[in] sender (object) The sender of the event.
    * @param[in] e (RoutedEventArgs) Arguments send with the event
    */
    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
      DialogResult = false;
      Close();
    }
  }
}

       
Backend for the variable editor

Summary

The cross platform project generator is a tool that combines CMake and Perforce to generate visual studio solutions for multiple platforms. It also allows you to create custom variables which can be used in your CMake scripts and it allows you to specify command line steps post generation. The main goal is to allow end users to only see variables relevant to them and to allow projects to be generated for PS4 as well.

Contributions

  • Everything (Personal Project)

Tools Used

visual studio
wpf
Doxygen

Team

Programmers: 1

Project length

6 weeks

Details

This project started out as a little experiment from one of the my previous school projects. Here we used a similar generator to generate projects for ps4 and windows. I wanted to expand on this and make it more user friendly / custimizable. I wrote this application from scratch (i.e I didn’t huse any code from the previous project). in addition to being able to generate cross platform I added the following things.

  • The option to edit / modify the variables yourself
  • The option to execute post - generate commands
  • The option to import / export settings
  • Integrated perforce
  • The option to deploy the application. This puts out a zip file with a version of the app that has all edit functionality stripped. this gives the end users a version that is much easier to understand and use.

Download