Did a bit of work on Quicksettings.js recently. Mostly based on some features suggested in issues and pull requests. A quick summary:
1. A few new controls:
addNumber. Basically the same as addRange, but displayed as a numeric text field with up and down buttons. Actual render may differ per browser / platform.
addDate. Where supported, will show a date field with a button to click that shows some kind of date picker. In Chrome you get an actual calendar. In some implementations, it’s just a text field. Input and output are both strings in the form “YYYY-MM-DD”.
addTime. Like date, but for time. String format “HH:MM” or “HH:MM:SS”. 24 hour time.
addPassword. Basically, addText, but text is hidden as asterisks, dots, or whatever the platform does with it.
All of those have corresponding bind, set and get methods as well.
2. Method chaining. Great suggestion. Now, all methods that do not actively return some value will return a reference to the panel itself. So you can do stuff like:
I’ve done some updates to QuickSettings over the last few weeks. First, I added quicksettings_minimal.css and quicksettings_minimal_dark.css style sheets, which bring everything down in size somewhat and get the range control sliders looking a bit more consistent across browsers and platforms. OK, OK, what I’m trying to say is that the whole thing looks more like good old MinimalComps. But it’s still all made with standard HTML controls and CSS.
I added a dropdown control that creates… well, a dropdown. Or an HTML Selection control, if you want to call things by their proper names.
There are now methods for setting values, changing range parameters and removing controls from the panel.
And the two most recent changes are really useful.
First, I added a setGlobalChangeHandler method. You pass a callback function to that and any time any control in the panel is changed, that callback will get called.
Secondly, I added a bunch of “bind” methods. These are analogous to the “add” methods, but rather than taking a callback function as the last argument, they take an object. When that control value changes, the property on that object that has the same name as the title you passed in will get assigned the new value of that control. Yeah… not sure that was very clear. Let’s try an example.
OK, so ‘model’ is an object that has a ‘visible’ property. This creates a checkbox. When the checkbox is clicked, model.visible will change to the value of the control. Simple, actually.
So these two latest changes make using the panel much more concise. You create a single model object, bind controls to properties on the model and set a global change handler. In the handler, you read the properties of the model. You can see it all in action in the binddemo.js file in the demos folder.
I’ve been using the panel myself in some personal projects, and I do really enjoy it. So the changes are coming from (my own) real world use.
Let’s recall the glory days of Flash and ActionScript. Initially, ActionScript was a scripting language with built in graphics and animation capabilities. There was a simple button object, but no other high level ui controls built in to the language.
Before long though, people figured out how to code them and all kinds of UI component libraries popped up. Macromedia created their own component set, which eventually evolved into Flex.
A stumbling block with virtually every ui component set created was styling and skinning, that is, making the controls look the way you wanted them to. This involved assigning multiple bitmaps to individual controls or classes of controls, or some kind of half-baked, compiled-in pseudo-CSS, and in many cases, in order to style a control, you had to subclass it and override the rendering methods.
For the most part, ui controls are fairly simple. Until you get into lists and data grids, and calendars, they’re all pretty straightforward views that respond to input and trigger events. But the styling aspect tended to bloat these component libraries all out of proportion to their usefulness and complicate them beyond belief.
I was doing a lot of experiments with math and physics,that often involved changing parameters at run time. I needed some simple buttons and sliders and checkboxes and a few other things that I could create quickly and easily to be able to do this. But I wasn’t happy with anything out there. So I created MinimalComps.
This was my own UI component set. It was designed to be drop dead simple to use. Generally, you could create and configure any control with a single line of code. Create it, pass in the parameters and an event callback. An important aspect of them was that I totally ignored all styling considerations. I gave them what I consider was a fairly attractive minimal look, and that’s what you got. Later I added support for dark and light themes, but that’s as far as that went.
MinimalComps were not designed to build websites or enterprise applications with. They were designed as an easy and very lightweight way to add standard user interaction to some kind of experimental, art or engineering piece. And they were hugely successful. People tell me they still use them to this day. They wound up being used in games and sites and all kinds of apps. If you do a Google image search for “MinimalComps”, you’ll see a bunch of examples. They were even spotted in an Adidas video for the Megalizer app made with them.
In short, they filled a niche and even outgrew that niche.
So I did it. And with that long-winded intro, I present QuickSettings.js
Rather than going through a long explanation of how to use them, I’ll just refer you to the github page, where the readme outlines all of the main methods.
I need to do some documentation, but looking through the source files should give you a pretty good idea of what’s going on. You’re smart people after all. If you make anything cool using them, be sure to share.
Just uploaded an update to the MinimalCompsJS project. The demo looks pretty much the same as the last one, but the components are completely refactored. Now, each component creates its own individual canvas element and adds it to a div (or any other element that can contain a canvas). So you don’t need to create any canvas at all to use them. This has massively simplified a lot of the code for redrawing and for mouse events.
One might ask, why use canvas at all? Why not just use text and styles? This would be possible, but using canvas as the base of each component has helped to unify how everything works and makes good use of the canvas drawing API, which I conceive will be useful as this goes forward.
I came up with a few nice little tricks in there too. One of the nicest, I think, is method chaining. Almost all publicly intended methods that don’t obviously return a value will return the component instance itself. This way you can create a component and chain together multiple methods on the end of it, and still wind up with a reference to the component you just created. Here’s a demo:
This is just like you see often in jQuery. Fun stuff. Looks odd at first, but I’ve learned to love it.
Label now has a setAlign method, which takes “left”, “center” or “right”.
A few things on the VSlider. One you see in the example above, bindLabel. Here, you pass in an instance of a Label, and a precision value in terms of how many decimal points to display. Now, whenever the slider value changes, it will update the label with its value. You also see some more chaining in the last line there, where we create a label and set its alignment, which returns the label to the bindLabel method.
Speaking of precision, the getValue method takes an optional precision value. If you pass nothing, you might get 3.14159. If you pass 2, you’ll get 3.14. Passing 0 will give you 3. You can also use negative numbers. If you pass -1, it will round 54321 to 54320. passing -2 will give you 54300, etc.
Also, you see setContinuous. True means, your change handler will fire continuously as you slide the slider. False means it will only fire when you release the slider.
A while back, when I first started playing with HTML5 and Canvas, I considered the idea of making a port of MinimalComps. I immediately rejected the idea as silly. I mean, if you’re in HTML, you already have UI controls, right? But I mentioned it to a few people and tweeted about it, and I was amazed how much interest there was in such a thing. At FOTB last month, I was asked about it a couple of times. So, I got to work.
As you can see, there is a Slider (vertical only), a PushButton, Label, and CheckBox. Not shown, but also fully working is a RadioButton. While there are various bells and whistles that could be added to what’s there, they seem to be pretty functional and solid.
Here’s a code sample from that demo:
var s1 = new mc.Slider(stage, 10, 30, onAngle);
var s2 = new mc.Slider(stage, 25, 30, onAngle);
var s3 = new mc.Slider(stage, 40, 30, onAngle);
s1.setSliderValues(0, Math.PI * 2, 1);
s2.setSliderValues(0, Math.PI * 2, 2);
s3.setSliderValues(0, Math.PI * 2, 3);[/php]
As you can see, they are very similar in use to the AS3 versions.
There were so many design decisions to make on this project. And while I obviously made certain decisions, I am by no means committed to any of them and am open to suggestions.
First and foremost is the decision to make the comps fully Canvas based. All components get added to a “stage” object, which is a wrapper around a canvas. Generally you would make a small canvas and use that for your component panel, or section off a rectangular area of another canvas for use by the controls. For me, this was the easiest way to get started, but I’m going to experiment with making each component have its own canvas. Then they can each be added to a div, with absolute positioning. This would actually simplify various things such as mouse events and redrawing. Currently, I have to listen to all mouse events on the stage and determine which component they belong to and farm them out. As for redrawing, some component drawing can be done just within the component bounds, but if anything is resized or repositioned, the entire canvas needs to be redrawn. If each component was its own DOM element, a lot of that would go away. Lots of stuff to experiment and keep my little brain busy for the next few weeks or months.
Anyway, I haven’t released the code officially, but feel free to grab it from view source and play around if you want. Each component has its own file, plus an overall MinimalComps.js file. Eventually, I’ll combine these all into one js file and minify it.
Doing some Android dev these days. Needed to check if a editable text field was empty or not. I had to dig around to find out how to do this. It turns out that an EditText’s getText() method returns an instance of Editable. You need to convert this to a string and then call equals(“”) on it. So you get this:
I’ve also been toying with the idea of moving the source over to github. I’ve been on a project with a client that uses git and finally got very familiar with it. I had many people begging me to use it for the comps. I pretty much decided on it a few weeks back, but wanted to straighten out this other stuff first.
So as of yesterday, the official MinimalComps repository is at:
First is on adding content to Windows and Panels. By default, if you added a child to one of these, it would just add it like any other child, positioning it from the top left of the parent’s position. In particular on the Window, this forced you to reposition your content so it wasn’t on top of the title bar. Also, in either case, if your content was larger than the parent, it would march on outside of the bounds of the parent.
To handle this, I created a content property on these components, which was positioned correctly, and masked the children added to it, so it looked correct. The recommended way of adding children to Panels or Windows was thus:
Unfortunately, this just wasn’t very obvious, and in retrospect, pretty stupid. The proper way would be to override addChild to add the child to the content automatically. So, that’s what I did. I also added a new addRawChild method to each of these components, in case you are doing some custom hackery that really required adding children to the component itself. The following should illustrate the change:
If you were already using content, you won’t see any changes, but you don’t need to use it any more. If you were adding children with addChild and repositioning manually, you’ll probably need to adjust your code to remove those manual adjustments, again, particularly on the Window.
This change also applies to Accordion and Scrollpane, which are based on Panels and Windows.
I also adjusted MinimalConfigurator to account for this, which mainly means I was able to remove the code that checked if the parent had a content property. Now it can always just addChild.
The next change was something else that’s been bugging me for a long time – the PushButton down state. It added an inner drop shadow, but otherwise was not very visible, particularly when using toggle = true. It wasn’t very obvious when a button was toggled in the down state.
So I added a new property on the Style class: Style.BUTTON_DOWN, which is used to redraw the button face when it is down, making it slightly different and much more noticeable. I added values for this to the light and dark themes. If you’ve created custom themes, you can add this to it.
SVN has been updated, and a new SWC and zipped source package have been uploaded to Google Code.
ps. If you used MinimalComps and want to join the conversation, check out the new Google group.