[Pas2js] Nyx framework (Mgr. Janusz Chmiel)

mister highball mr.highball at hotmail.com
Fri Oct 9 20:45:24 CEST 2020


> ...This compiler and units have allowed Me to finally create quiz which can
> monitor even 40 editable fields at The same time. The advantage of this
> approach is, that it is not necessary to fill out questions chronologically.
> Respondent can decide The order. Respondent is not being forced to confirm
> The right answer by using some confirmation button or by even pressing Enter
> key.
> It is excellent dynamic process...

I've put together a demo showing how you could add labels to editable fields (as mentioned in a prior email) and after reading one of your use cases (dynamic quiz fields) I changed it this morning to support a more dynamic approach.

I created the demo using the standard "TBrowserApplication" template and implemented a BuildUI(AInputs) method. the browser app call the BuildUI method in the .DoRun() but first adds a list of input names (think of these as your quiz questions). AInputs is just a string list, so you could populate this list from a website or a database (or anything dynamically). The BuildUI method handles all of the nyx related logic for setting up a user interface object, adding the inputs to the UI, then adding the labels to be "parented" to them, and finally rendering to the dom.

I've pushed this example to the nyx repository, so if you have it cloned, all you would need to do is "git pull". Below I've also listed the important methods as they are right now if it's easier to look at them here, but the full example can be found here:
https://github.com/mr-highball/nyx/tree/master/demos/browser/input-labels

```
procedure TInputLabels.doRun;
var
  LInputs : TStringList;
begin
  //here we create a stringlist to hold the input "names". these could be
  //pulled from a db, web request, or any other dynamic source, but to test
  //we'll just add them manually
  LInputs := TStringList.Create;
  LInputs.Add('First Name');
  LInputs.Add('Middle Name');
  LInputs.Add('Last Name');
  LInputs.Add('Did this question show correctly?');
  BuildUI(LInputs);
  LInputs.Free;
end;
```
```
procedure TInputLabels.BuildUI(const AInputs: TStrings);
var
  I: Integer;
  LLayout: INyxLayoutRelational;
  LPropLayout : INyxLayoutProportional;
  LContainer: INyxContainer;

  (*
    method to parent a label to an element, used in a "foreach" call
    on the UI's elements collection
  *)
  procedure AddLabelToElements(const AElement : INyxElement);
  var
    LText: INyxElementStaticText;
    LBounds: INyxRelationalBounds;
  begin
    //create and add the text to the UI
    LText := NewNyxStaticText;
    FUI.ContainerByIndex(I).Add(LText);

    //set the text to the element's name
    LText
      .UpdateText(AElement.Name)
      .UpdateFormat([sfBold]); //we'll bold for emphasis

    //setup a bounds that anchors this text element to the input element
    LBounds := NewNyxRelationalBounds;
    LBounds
      .UpdateTop(-40)
      .UpdateVertAlignment(vaTop); //anchor to top

    //add the text to be managed by the relational layout
    LLayout.Add(LText, AElement, LBounds);
  end;

  (*
    this method will setup proportional positions for all of
    the input elements based on the index using the following formula:
      Position = (Index + 1) * 0.10 (for the top)
  *)
  procedure PositionInputsByIndex(const AElement : INyxElement);
  var
    J: Integer;
  begin
    FUI.ContainerByIndex(I).Elements.IndexOf(AElement, J);
    LPropLayout.Add(
      AElement,
      INyxProportionalBounds(NewNyxProportionalBounds
        .UpdateTop(Succ(J) * 0.10)
        .UpdateLeft(0.5) //position input to the center of the container
        .UpdateHorzAlignment(haCenter))
    );
  end;

begin
  FUI := NewNyxUI;
  LLayout := NewNyxLayoutRelational;
  LPropLayout := NewNyxLayoutProportional;
  LContainer := NewNyxContainer;

  //add inputs based on the strings and update the "name" property.
  //we'll use this in the AddLabelToElements method as the label text
  for I := 0 to Pred(AInputs.Count) do
    LContainer.Add(NewNyxInput.UpdateName(AInputs[I]));

  //add labels and size the container
  FUI
    .AddLayout(LLayout, I) //this layout controls the label positioning
    .AddLayout(LPropLayout, I) //this layout controls the input positioning
    .AddContainer(LContainer, I)
    .ContainerByIndex(I)
      .UpdateSize( //make the container take up 100% of the screen
        NewNyxSize
          .UpdateHeight(1)
          .UpdateWidth(1)
          .UpdateMode(smPercent) //use percent mode
      )
    .Container
      .Elements
        .ForEach(@PositionInputsByIndex);


  //now that we've added all the inputs render to the screen so they have
  //positions, then we need to add the labels and render again (we do this
  //because of the dynamic nature of adding labels, normally only one render would be needed)
  FUI.Render();
  LContainer.Elements.ForEach(@AddLabelToElements);
  FUI.Render();
end;
```

-Highball
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/pas2js/attachments/20201009/568278cd/attachment.htm>


More information about the Pas2js mailing list