Spec: "pluggable" widgets / label-input layout?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Spec: "pluggable" widgets / label-input layout?

Daniel Lyons
Supposing I have a domain model, Activity, which looks like this:

Object subclass: #Activity
        instanceVariableNames: 'title cost'
        classVariableNames: ''
        category: 'PERT'

Then I have the expected accessors for title and cost.

I make a Polymorph dialog for editing one of these things like so:

PolymorphEditActivity>>edit: anActivity
        | builder content dialog |
        activity := anActivity.
        builder := Smalltalk ui theme builder.
       
        content := builder newLabelGroup: {
                'Title' -> (builder newTextEntryFor: self activity getText: #title setText: #title: help: 'The title of the activity').
                'Cost' -> (builder newTextEntryFor: self activity getText: #cost setText: #cost: help: 'The cost of the activity')
        }.
        dialog := builder newPluggableDialogWindow: 'Edit activity' for: content.
        ^ builder openModal: dialog.

*First question*: how do I return a value from the dialog?

Now the Spec version of this I have looks like this:

ComposableModel subclass: #SpecEditActivity
        instanceVariableNames: 'activity titleLabel costLabel titleWidget costWidget'
        classVariableNames: ''
        category: 'PERT'

SpecEditActivity>>initializeWidgets
        "Set up the widgets for the dialog"
        titleWidget := self newTextInput.
        titleLabel := self newLabel.
        costWidget := self newTextInput.
        costLabel := self newLabel.
       
        titleLabel label: 'Title:'.
        costLabel label: 'Cost:'.
        self focusOrder
                add: titleWidget;
                add: costWidget

SpecEditActivity>>initializePresenter
        super initializePresenter.
        titleWidget whenTextChanged: [ :newText | activity title: newText ].
        costWidget whenTextChanged: [ :newCost | activity cost: newCost ]

Then on the class side of things, I have this layout:

SpecEditActivity class>>layout
        <spec>
        ^ SpecLayout composed
                newColumn: [ :column |
                        column
                                newRow: [ :row |
                                        row
                                                add: #titleLabel;
                                                add: #titleWidget ];
                                newRow: [ :row |
                                         row
                                                add: #costLabel;
                                                add: #costWidget ] ];
                yourself

I make all the expected "getter" methods.

I can see how to get the model value out: I do something like this:

activityDialog := SpecEditActivity new openDialogWithSpec; yourself.
activityDialog model activity

I have two questions about the Spec side of the house:

1. The title/costWidget whenTextChanged: stuff. With Polymorph, I can just say, here's an object, here's the getter/setter, deal with it. Does Spec have anything like this, or do you have to do this manual data shuffling? Is there an example I can learn from?

2. This layout is a bit on the ugly side. I looked at the examples and saw usage of the expert layout with asking how tall a line is. Is that the best that can be done, or is there something more like Polymorph's label layout that can be used instead?

Thanks for your time and patience!


Daniel Lyons




Reply | Threaded
Open this post in threaded view
|

Re: Spec: "pluggable" widgets / label-input layout?

Nicolai Hess

2014-12-20 5:49 GMT+01:00 Daniel Lyons <[hidden email]>:
Supposing I have a domain model, Activity, which looks like this:

Object subclass: #Activity
        instanceVariableNames: 'title cost'
        classVariableNames: ''
        category: 'PERT'

Then I have the expected accessors for title and cost.

I make a Polymorph dialog for editing one of these things like so:

PolymorphEditActivity>>edit: anActivity
        | builder content dialog |
        activity := anActivity.
        builder := Smalltalk ui theme builder.

        content := builder newLabelGroup: {
                'Title' -> (builder newTextEntryFor: self activity getText: #title setText: #title: help: 'The title of the activity').
                'Cost' -> (builder newTextEntryFor: self activity getText: #cost setText: #cost: help: 'The cost of the activity')
        }.
        dialog := builder newPluggableDialogWindow: 'Edit activity' for: content.
        ^ builder openModal: dialog.

*First question*: how do I return a value from the dialog?

You don't need the return something, you don't even need to use a separate instvar in the PolymorphEditActivity.
If "anActivity" is a Activity with the accessor #title / #title: #cost/#cost:, the PluggableDialogWindow will change this
attributes only if the dialog is closed with "OK"


    | anActivity builder content dialog |
    anActivity := Activity new.
    anActivity title: 'what'.
    anActivity cost: '100'.
    builder := Smalltalk ui theme builder.
    content := builder
        newLabelGroup:
            {('Title'
                ->
                    (builder
                        newTextEntryFor: anActivity
                        getText: #title
                        setText: #title:
                        help: 'The title of the activity')).
            ('Cost'
                ->
                    (builder
                        newTextEntryFor: anActivity
                        getText: #cost
                        setText: #cost:
                        help: 'The cost of the activity'))}.
    dialog := builder newPluggableDialogWindow: 'Edit activity' for: content.
   builder openModal: dialog.
anActivity inspect




Reply | Threaded
Open this post in threaded view
|

Re: Spec: "pluggable" widgets / label-input layout?

Nicolai Hess
In reply to this post by Daniel Lyons
The spec part of your question:

2014-12-20 5:49 GMT+01:00 Daniel Lyons <[hidden email]>:
Supposing I have a domain model, Activity, which looks like this:

Object subclass: #Activity
        instanceVariableNames: 'title cost'
        classVariableNames: ''
        category: 'PERT'

Then I have the expected accessors for title and cost.

Now the Spec version of this I have looks like this:

SpecEditActivity>>initializePresenter
        super initializePresenter.
        titleWidget whenTextChanged: [ :newText | activity title: newText ].
        costWidget whenTextChanged: [ :newCost | activity cost: newCost ]

Then on the class side of things, I have this layout:

SpecEditActivity class>>layout
        <spec>
        ^ SpecLayout composed
                newColumn: [ :column |
                        column
                                newRow: [ :row |
                                        row
                                                add: #titleLabel;
                                                add: #titleWidget ];
                                newRow: [ :row |
                                         row
                                                add: #costLabel;
                                                add: #costWidget ] ];
                yourself

I make all the expected "getter" methods.

I can see how to get the model value out: I do something like this:

activityDialog := SpecEditActivity new openDialogWithSpec; yourself.
activityDialog model activity

First, please don't add a method #layout on the class side, this conflicts with the notion of "Slots" (bug reported, but it is not fixed yet)

 

I have two questions about the Spec side of the house:

1. The title/costWidget whenTextChanged: stuff. With Polymorph, I can just say, here's an object, here's the getter/setter, deal with it. Does Spec have anything like this, or do you have to do this manual data shuffling? Is there an example I can learn from?

If you just want to show an edit dialog, I would separate the Acitivty-Model (two textfields) from your domain model "Activity". Then you don't need this "whenTextChanged". This is only needed if other elements from the model
depend on the textfield content.

Now you can use spec to only show a dialog and after closing this dialog you can retrieve the values with

activitiy title: theDialogModel titleWidget text
activity cost:  theDialogModel costWidget text
....

 

2. This layout is a bit on the ugly side. I looked at the examples and saw usage of the expert layout with asking how tall a line is. Is that the best that can be done, or is there something more like Polymorph's label layout that can be used instead?

you can define the hight of the rows based on the inputfield default height (based on the current theme) (ComposableModel class >>#defaultInputHeight
 
Take a look at Komitters CredentialEditor


Thanks for your time and patience!


Daniel Lyons





Reply | Threaded
Open this post in threaded view
|

Re: Spec: "pluggable" widgets / label-input layout?

Daniel Lyons

On Dec 20, 2014, at 4:06 AM, Nicolai Hess <[hidden email]> wrote:

The spec part of your question:

2014-12-20 5:49 GMT+01:00 Daniel Lyons <[hidden email]>:
Supposing I have a domain model, Activity, which looks like this:

Object subclass: #Activity
        instanceVariableNames: 'title cost'
        classVariableNames: ''
        category: 'PERT'

Then I have the expected accessors for title and cost.

Now the Spec version of this I have looks like this:

SpecEditActivity>>initializePresenter
        super initializePresenter.
        titleWidget whenTextChanged: [ :newText | activity title: newText ].
        costWidget whenTextChanged: [ :newCost | activity cost: newCost ]

Then on the class side of things, I have this layout:

SpecEditActivity class>>layout
        <spec>
        ^ SpecLayout composed
                newColumn: [ :column |
                        column
                                newRow: [ :row |
                                        row
                                                add: #titleLabel;
                                                add: #titleWidget ];
                                newRow: [ :row |
                                         row
                                                add: #costLabel;
                                                add: #costWidget ] ];
                yourself

I make all the expected "getter" methods.

I can see how to get the model value out: I do something like this:

activityDialog := SpecEditActivity new openDialogWithSpec; yourself.
activityDialog model activity

First, please don't add a method #layout on the class side, this conflicts with the notion of "Slots" (bug reported, but it is not fixed yet)

Don't add a method to do the layout or don't name it #layout? The tutorial doesn't say what to name the method, just that it can be named anything using the pragma.

 

I have two questions about the Spec side of the house:

1. The title/costWidget whenTextChanged: stuff. With Polymorph, I can just say, here's an object, here's the getter/setter, deal with it. Does Spec have anything like this, or do you have to do this manual data shuffling? Is there an example I can learn from?

If you just want to show an edit dialog, I would separate the Acitivty-Model (two textfields) from your domain model "Activity". Then you don't need this "whenTextChanged". This is only needed if other elements from the model
depend on the textfield content.

Now you can use spec to only show a dialog and after closing this dialog you can retrieve the values with

activitiy title: theDialogModel titleWidget text
activity cost:  theDialogModel costWidget text
....

OK, but two questions:

1. How do I know when the dialog is finished?
2. That's going to be a lot of manual copying compared to the Polymorph version. Is that just life or are there "pluggable" widgets that will talk to my model directly?

 

2. This layout is a bit on the ugly side. I looked at the examples and saw usage of the expert layout with asking how tall a line is. Is that the best that can be done, or is there something more like Polymorph's label layout that can be used instead?

you can define the hight of the rows based on the inputfield default height (based on the current theme) (ComposableModel class >>#defaultInputHeight
 
Take a look at Komitters CredentialEditor

Thanks!



Thanks for your time and patience!


Daniel Lyons

— 
Daniel Lyons



Reply | Threaded
Open this post in threaded view
|

Re: Spec: "pluggable" widgets / label-input layout?

stepharo


Don't add a method to do the layout or don't name it #layout?

dont name it layout.


The tutorial doesn't say what to name the method, just that it can be named anything using the pragma.

 

I have two questions about the Spec side of the house:

1. The title/costWidget whenTextChanged: stuff. With Polymorph, I can just say, here's an object, here's the getter/setter, deal with it. Does Spec have anything like this, or do you have to do this manual data shuffling? Is there an example I can learn from?

If you just want to show an edit dialog, I would separate the Acitivty-Model (two textfields) from your domain model "Activity". Then you don't need this "whenTextChanged". This is only needed if other elements from the model
depend on the textfield content.

Now you can use spec to only show a dialog and after closing this dialog you can retrieve the values with

activitiy title: theDialogModel titleWidget text
activity cost:  theDialogModel costWidget text
....

OK, but two questions:

1. How do I know when the dialog is finished?
2. That's going to be a lot of manual copying compared to the Polymorph version. Is that just life or are there "pluggable" widgets that will talk to my model directly?

 

2. This layout is a bit on the ugly side. I looked at the examples and saw usage of the expert layout with asking how tall a line is. Is that the best that can be done, or is there something more like Polymorph's label layout that can be used instead?

you can define the hight of the rows based on the inputfield default height (based on the current theme) (ComposableModel class >>#defaultInputHeight
 
Take a look at Komitters CredentialEditor

Thanks!



Thanks for your time and patience!


Daniel Lyons

— 
Daniel Lyons