Spec - how to change the color (or background color) of a presenter - smalltalk

I want to change the background color of a SpTextInputFieldPresenter
e.g. to provide a visual feedback of the input, I want to react to whenTextChangedDo: and change the background color of the field to show if the input is correct or wrong. I know this is not the best for everybody, but I still want to try it.
How can I do without hacking?

Spec previews the use of styles to change (up to a point) how a component looks.
Styles are added to an application (an instance of SpApplication or child of it) and can be used by any presenter that is part of the application.
Styles can be seen as CSS stylesheets, and in the case of Gtk they actually are CSS stylesheets, but in the case of Morphic backend they have a complete different implementation (you can see all properties you can define in the SpPropertyStyle hierarchy.
The following code will show how to
declare styles (in a scripting way, in a production scenario styles would be likely defined in a configuration for the application).
use them by adding or removing them.
app := SpApplication new.
"If using Morphic"
app addStyleSheetFromString: '.application [
.red [ Draw { #color: #red } ],
.green [ Draw { #color: #green } ]
]'.
"If using GTK (you need to choose one, both options are not possible at the same time)"
app useBackend: #Gtk.
app addCSSProviderFromString: '
.red { background-color: red }
.green { background-color: green }
'.
presenter := SpPresenter new.
presenter application: app.
presenter layout: (SpBoxLayout newTopToBottom
add: (textPresenter := presenter newTextInput) expand: false;
addLast: (SpBoxLayout newLeftToRight
add: (presenter newButton
label: 'Red';
action: [ textPresenter removeStyle: 'green'; addStyle: 'red' ];
yourself);
add: (presenter newButton
label: 'Green';
action: [ textPresenter removeStyle: 'red'; addStyle: 'green' ];
yourself);
yourself)
expand: false;
yourself).
presenter asWindow
title: 'Example applying styles';
open
This will produce (with the Gtk3 backend) this output:

Related

Spec - use ctrl-S (or cmd+s) to save text entry

is there a way in SpTextPresenter and SpTextInputFieldPresenter to use ctrl+S (or cmd+S in mac) to save text entry?
Old pharo components (notably old spec but this comes since before, when components when built on plain morphic) were allowing to "accept" contents by pressing <meta+S> (and cancelling the edition by using <meta+L>).
Is there a way to replicate this behavior in current Spec?
Spec permits to define "default" submit/reset events to provide old behavior.
Ok, this is an easy answer, but somehow complicated for some users since they expect the old behavior and this does not works like that anymore.
So first I need to explain why old behavior is no longer available :)
Thing is, old components where a mix of different things: they were plain UI widgets while also model containers in the spirit of old MVC (Model View Controller). So they mixed Model (the keep of the status) and the view (the display of the component). For this reason, old components had an initial status and you needed to accept that status (you got it, using <meta+S>) to make it being transferred to the model part.
This mix of responsibilities lead to different workarounds, like the addition of the autoAccept property to make the component copy its value it change of it.
When designing the new version of Spec we decided to not keep this behavior that looked hacky and was causing inconsistencies in the API and in consequence anyone wanting the old behavior need to make it explicitly in their own components.
So, how to get old behavior?
This is the question after all!
We have added two methods to allow somehow same functionality: whenSubmitDo: and whenResetDo:. This can be combined with whenTextChangedDo: to mark/unmark a dirty property.
Here is an example, Is a little bit verbose, but is also easy to create your own components with this behavior predefined and reuse them in your application:
app := SpApplication new.
"If using Morphic"
app addStyleSheetFromString: '.application [
.dirty [ Container { #borderColor: #red, #borderWidth: 1 } ],
.notDirty [ Container { #borderColor: #transparent, #borderWidth: 1 } ]
]'.
"If using GTK (you need to choose one, both options are not possible at the same time)"
app useBackend: #Gtk.
app addCSSProviderFromString: '
.dirty {
border-color: red;
border-width: 1px; }
'.
presenter := SpPresenter new.
presenter application: app.
presenter layout: (SpBoxLayout newTopToBottom
add: (textPresenter := presenter newTextInput) expand: false;
yourself).
text := ''.
textPresenter
text: text;
whenTextChangedDo: [ :aString |
aString = text
ifTrue: [ textPresenter removeStyle: 'dirty'; addStyle: 'notDirty' ]
ifFalse: [ textPresenter removeStyle: 'notDirty'; addStyle: 'dirty' ] ];
whenSubmitDo: [
text := textPresenter text.
('Submitted ', text) crTrace.
textPresenter
removeStyle: 'dirty';
addStyle: 'notDirty' ];
whenResetDo: [
textPresenter
text: text;
removeStyle: 'dirty';
addStyle: 'notDirty' ].
presenter asWindow
title: 'Example submit/reset text component';
open
This will produce (with the Gtk3 backend) this output:

Sencha Touch 2 Component in list emptyText

I have a list component that I want to display a button to send a suggestion for the data to be included if it turns up no results.
List component itself is implemented like this:
{
xtype: 'list',
itemTpl: '{name}',
// This is not ideal!
emptyText: [
'<div class="x-button-normal x-button">',
'<span class="x-button-label">',
'Suggest <i><span id="suggest-name"></i>',
'</span>',
'</div>'
].join(''),
store: 'TheStore'
}
And this is the handler for the search field that simply sets a substring filter on the store:
'keyup': function(self, e, eOpts) {
queryString = self.getValue();
 
var store = Ext.getStore('TheStore');
store.clearFilter();
 
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('name'))) {
return true;
};
return false;
});
// Changes the button so it shows name
document.getElementById('suggest-name').innerText = queryString;
}
},
Right now, I have the emptyText set to some simple HTML that emulates the look of a Sencha Touch button, but this means I have none of the button behaviour since it's not tied into the component system (such as being depressed when tapped). How can I set the emptyText attribute (or emulate it) since a proper button is displayed instead?
Try to view the two screencasts below
Sencha Touch - Intro to Nested List Component
Sencha Touch 2 -
Intro to List Component
I know it's about 2 years too late... but I ran into the same problem as #Hampus Nilsson and when I found the solution, I figured if I was running into this 2 years later, others might run into it as well.
With that said... I'm currently running Sencha Touch version 2.3.1. The solution, as it pertains to that version, was really easy to implement, just super tricky to find. The problem is that Sencha has a CSS property on the emptyText component (x-list-emptytext class) that is ignoring all pointer interactions called pointer-events: none; (who knew?!)
This property is found in:
[sdk_root]/resources/themes/stylesheets/sencha-touch/base/src/dataview/_List.scss
.x-list-emptytext {
text-align: center;
pointer-events: none; // THIS ONE!!
font-color: #333333;
#include st-box();
#include st-box-orient(vertical);
#include st-box-pack(center);
}
To fix this, simply override that property in your own sass/css. I chose to override it with pointer-events: inherit; but your mileage may vary.
THEN, all you need to do is setup a listener on your list, I recommend in the initialize function of your list class, like the so:
this.emptyTextCmp.element.on({
delegate: '.x-button-normal',
scope: this,
tap: this.yourCustomFunction
});
Where this is your list component. It's important to note that you need a "." in front of the class name of your delegate. In the above example, I set the delegate to: '.x-button-normal', because that was one of the two classes listed in the question's code. I could've also used '.x-button'. If it were me, I'd give your html an additional class, to be used as the delegate, that helps identify it a little better, instead of just using the default Sencha class as your delegate. That's an opinion, not a requirement.
That's it, I hope this helps someone else!

Displaying Custom Images in 'tools' config options of ext.grid.panel

I am only a month old with extjs and still experimenting. My question is: I have a grid panel and within it the 'tools' config options. I am using this to enable/disable a Ext.grid.feature.Grouping variable. The 2 handler functions have the logic to disable/enable the 2 views by clicking on the 2 'cross' buttons that appear on the right side of the header. The logic is fine. However, I would like to display my set of custom images in place of the 'cross' buttons. Can this be done? If yes, how? Do I need to make some changes in the css code for that?
I have looked into the documentation and also done a good search but nothing seems to answer my question.
Specify a custom type config on your tools:
Ext.create('Ext.grid.Panel', {
...
tools: [
{
type: 'enable-grouping',
handler: function() {
...
}
},
{
type: 'disable-grouping',
handler: function() {
...
}
}
]
});
Then define the following classes in a stylesheet to style your new tools:
.x-tool-enable-grouping {
background-image: url('path/to/tool/image/enable-grouping.png');
}
.x-tool-disable-grouping {
background-image: url('path/to/tool/image/disable-grouping.png');
}
The size of a tool image should be 15 x 15 px

Icons available for ExtJS's Panel's "tool" buttons

How can I set icon used in my Panel's "Title Bar"? Maybe I need to add an image myself, but if so I suppose I need to define or configure that somewhere?
{
xtype: 'treepanel',
title: 'Projects',
width: 200,
store: Ext.data.StoreManager.lookup('projects'),
tools: [
{
type: 'add', // this doesn't appear to work, probably I need to use a valid class
tooltip: 'Add project',
handler: function() {
console.log('TODO: Add project');
}
},
...
]
},
There are a set of 25 icons that can be specified by using the type config.
check http://docs.sencha.com/ext-js/4-0/#!/api/Ext.panel.Tool-cfg-type
To get add symbol use
tools:[{
type:'plus',
tooltip: 'Add project',
// hidden:true,
handler: function(event, toolEl, panel){
// Add logic
}
}]
the specified type:'add' is not in the list
If you want to add your own tool type and be able to assign it an image of your own, you can do the following:
Add a css class in your css file:
.x-tool-mytool { background-image: url(path_to_your_image_file) !important; }
Then in your tools, simply use 'mytool' as the type:
{
type:'mytool',
tooltip: 'This is my tool',
handler: function(event, toolEl, panel){
// my tool logic
}
}
Make sure that you use the same name in tool's type as you used for the css class suffix.
according to the ExtJS documentation, these predefined types are available:
collapse, expand, maximize, minimize, resize, restore, move, close
minus, plus, prev, next, pin, unpin, search, toggle, refresh
save, print, gear, help
right, left, up, down
one can enter whatever type one wants:
{type: 'YOURTYPE'}
while providing a 15px icon - or preferably icon sprites
(the background-position certainly not applies for single icons, but icon sprites):
.x-tool-img.x-tool-YOURTYPE{
background: url('../images/custom_tool_sprites.png') no-repeat 0 0;
}
sources: Ext.panel.Tool-cfg-type, codefx.biz.
I think you mean "set buttons used in my Panel's Title Bar", not "set icon". You can use buttons config of Panel, not tools:
buttons: [{
text: 'Add',
tooltip: 'Add project',
handler: function() {
console.log('TODO: Add project');
}
}]
You can use other configurations like bbar (bottom bar), fbar (footer), tbar (top), lbar (left), rbar (right) for position the toolbar. One small notice is the config objects in buttons have the default xtype as button, so you don't need to explicitly specify them.

Set a default UI across all components in Sencha Touch

Within Sencha Touch, is it possible to define a default UI , like "light" or "dark", that applies to all components (unless overwritten explicitly)?
The aim is to avoid having to declare ui: "dark", or any custom UI that is made, for every element.
Cheers!
You can try this:
Ext.apply(Ext.Component.prototype, {
getUi: function() {
var defaultUi = 'light';
// value of [this.config.ui] is ignored here
// we can use something like forcedUi
return (this.forcedUi) ? this.forcedUi : defaultUi;
}
})
The disadvantage of this code is that we need to specify another variable for applying ui different from 'light' (because variable 'ui' via getUi() will always return 'light'):
...
items: [{
xtype: 'button',
forcedUi: 'dark'
}]
...
I am stuck on Touch 1.1 so sunsay's solution didn't work for me, but this did:
Ext.CustomToolbar = Ext.extend(Ext.Toolbar,
{
ui:'app'
});
Ext.reg('toolbar', Ext.CustomToolbar);
So, it's still component-by-component-type, but not component-by-component-instance. And since you can overwrite the "reg", no need for custom x-types all over the place, either.
I assume that you know about sencha touch styles and themes. Otherwise you can download a pdf file from this link which clearly describes about how to do it...
http://f.cl.ly/items/d9df79f57b67e6e876c6/SenchaTouchThemes.pdf
In it they are mentioning about scss file where you can specify the base-color, ie
$base-color: #4bb8f0 ;
$base-gradient: 'glossy';
Then run it ... you can see the toolbars and buttons created with the color and gradient you have mentioned.