Archive

Archive for April, 2015

Beta Blues? Fret ye not!

April 24, 2015 2 comments

Smart Mobile Studio recently went into it’s second beta phase, sporting a much faster RTL and snappy compiler / UI. You also get a ton of juicy new features, like raw memory support (including good old allocmem and freemem), streams, websocket and much, much more.

But some people have reported problems with the built-in browser. As you all know we use a custom version of Chromium, which is a webkit based project. And one of the chores we had was to update to the latest webkit build. So the built-in browser in the Smart Mobile Studio beta is actually the latest.

Sadly webkit is a very, very hectic project. It changes on a daily basis, with hundreds of programmers working on it and applying fixes, introducing new features and generally doing what coders do. So grabbing “the latest” version is not as simple as it sounds.

The short story is: it’s unstable and css-effects are often the victim. Even something as simple as moving from one from to the other can be affected. Since not everyone has reported this one, i suspect is has to do with hardware and the capabilities of your graphics card. But either way, webkit should not behave like this – so it’s a clear case of a buggy build.

So either way, if you experience problems with the built in browser your have two options..

Copying the new RTL to your existing SMS installation works fine

Copying the new RTL to your existing SMS installation works fine

Turn off the built in browser

Yes, it’s that simple. I take it for granted that you have installed a couple of browsers on your system, preferably chrome, safari, the latest internet explorer and Firefox. So all you have to do is to define the browser you want to use in the preferences dialog, and that’s it.

Copy the RTL and use version 2.1.2.3592

If you dont want to play with the IDE but just see the RTL improvements, then there is no shame in just copying the new RTL into your older Smart Mobile Studio installation. Remember to back up your present RTL folder first (!)

So If you just want to see what SMS is all about and get an impression of the codebase and what you can do, then you can also request a trial version and again – copy over the new RTL.

But — remember: do not copy the package files (!) This is very important since our package structure can embed RTL code, leading to conflict if the same file exists in two places.

This is not the optimal way of going about it – but until we issue the third beta candidate, it’s not much else you can do. And no – you cannot copy the old webkit DLL files. These builds have different headers and functions, so doing that will crash for sure.

Is native outdated? Debate!

April 24, 2015 Leave a comment
I sort of subscribe to the chaos theory

I sort of subscribe to the chaos theory

Life has its ups and downs, but this one is a case that really makes me stop and think. They say the moment you reach 30, you lose your immortality. In the sense that you no longer regard yourself as immortal, infallible and a list of other power-words. It’s the age when you realize that you are no longer in the front-seat of all things new and bright, and that in fact you are heading for death.

With that gloomy intro, here is the pickle that has made me really question what programming and being a “native” developer means: Is native code outdated? I write that because the more young programmers I meet, the less native code I encounter. And it’s really scary! I mean how do you build a custom server? Not just a server that does something different, but a truly custom, never before done, truly unique and brand new – without the speed power that native code provides?

But these kids have a completely different take on it, which makes me feel so very, very old. But it also makes me want to educate them about the differences, with limited success so far.

Once in a while I meet up with younger programmers, some at work and others through IRC or Facebook to check out the latest developments. It’s mostly open forum so everyone posts ideas, links, code, references – and we all bitch and moan about what we don’t like (or envy I guess, people do that as well online).

What throws me is that native code is taking up less and less space in the minds of young programmers. Programmers who, unlike our generation I presume, have primarily grown up with free development tools and open-source libraries. So in their mind paying for anything related to programming is just not where it’s at. Perhaps this is why Microsoft has suddenly transformed into the sugar daddy of high-tech? Time will tell perhaps.

But either way, the majority of these free tools must be running on what ultimately has be, it bloody has to be (!) native code. I accept that the platform itself can be script based, perhaps generating bytecodes or p-code. But native must by virtue of how the hardware is designed, remain relevant. Right?

The p-code thing

If you don’t know the difference between byte-codes and p-codes,  they are essentially the same thing. But instead of representing your commands as bytes and small records, like say java or dot net does; P-codes have bytes which represents offset values into a runtime library. So instruction $0001 would execute command #1, and $000F would execute command number 15 (or 16 if you count from zero). The downside of p-code compilers is that they are extremely fragile. If you alter even a single byte the whole system can crash, so modern implementations use CRC and checksum validation before executing.

Since a p-code represents an offset into an array of pointers, they execute extremely fast. In many cases it can be hard to distinguish native programs from well written p-code programs. It depends wildly on the language at hand naturally, but all in all p-codes just pounds every ounce of clock cycles out of the processor.

The downside is that it’s fragile like hell. A single altered byte in a p-code program can crash the program with spectacular access-violations. Hence modern implementations are often cluttered with CRC checks and identifiers. But they are fast, much faster than translating byte-codes.

Right, now back to the topic at hand.

Is the future scripted?

A part of me want to say yes, because there is more than enough power in modern script-engines to create really powerful desktop applications, services and/or games. But a script engine can’t write itself. You can’t write a script engine in JavaScript because sooner or later someone has to write JavaScript, if you get what I mean. Somewhere along the line a programmer has to use a language which compiles to native, be it C / C++, object pascal or some other native language. I even remember a guy writing his own operating system in BlitzBasic, but he used like 70% inline assembler so I’m not sure he qualifies as a basic representative.

So while it’s tempting to say yes, considering the widespread adoption of languages like python, pearl, ruby and javascript – it just can’t be true. And that statement has launched an avalanche of well-meaning but ignorant feedback from my younger friends; who doesn’t know what native is all about and as such protect their faith in scripting to the death.

So no. You can’t get through to them.

The smart thing

Since myself and the group of programmers I work with are marketing object pascal as the best language for web and cloud development; and we have adapted object pascal to be more in-tune with how development in our day and age works, like anonymous procedures, records, properties and whatnot — i should be pro 100% script right?

Well I’m not. Smart Mobile Studio represents, in my view, one of the best solutions for writing cloud based software. Primarily because you have full access to nodeJS, which in turn mean you can write both the server and client from the same codebase.

The secret lab that shall not be named

The secret lab that shall not be named

But it’s only the best solution because the medium, namely the browser and JavaScript, is so fluid and flamboyant in nature. You can do some tricks in JavaScript that would be suicide under native languages, but in the padded room of JavaScript everything goes.

But does that mean I have become sort of “anti native code”? Absolutely not. In fact I love Delphi to pieces, and C# (native mono compilation) and I even have an off the record love affair with C++. First of all because it’s the only thing I know how to do, part from JavaScript which I’m very, very good at. But I also think it’s important for all of us to get our ducks in a row.

The view I have is that scripting is not really programming is it? I mean “really” programming. Scripting for me is a bit like sculpting. You sit down and sculpt data structures and setup boundaries using a language which, subjectively speaking, is the intellectual equivalent of putty rather than brick. So it’s a bit like carving a madonna out of a piece of soap versus a solid piece of engineering forged in steel.

Or how about this: native programming is a bit like coding a gene-pool, while scripting is the same as body-building. With scripts you carve out the form, the relations and setup the pathways between them. But without the underlying generic programming, there would be no intelligence or program to carry out the build-plans to begin with.

Native languages feel more edgy to me, more solid and concrete. You can’t cheat and get away with it under native object pascal or C, because it wont even compile. You are also closer to the hardware since the code you write is ultimately the binary pattern fed to the processor. While scripting languages are.. well, fed to a dispatcher after going through a lookup table.

A young solution

I really am amazed by how the younger generation solve things, because they are – without knowing it – doing a better job than we did 20 years ago. Instead of writing a server from scratch like we would probably do for a new piece of technology, they implement the “new” bit using the protocols already in place. So they get the job done, but in a way very different from ours.

So the new server is not a new server, it’s the same old HTTP server you have been using for 15 years, except now the URL’s are command and form-fields are parameters. Things like REST was not invented by a seasoned developer, it’s actually a perversion of the HTTP protocol if you like. But it works, and it’s even turned into a standard now.

Kids are growing up with pre-fabricated clouds

Kids are growing up with pre-fabricated clouds where we had Atari and C-64.

Same with python. You dont setup a cluster with C or object pascal, no you use python and it will execute parts of the same program on different computers to spread the payload. And that makes sense, since native code would be much harder to disperse over X number of nodes. So suddenly scripting makes sense over native. At least in that particular scenario.

The only real problem with “young thinking” is that it doesn’t generate money the same way we are used to. When you use only free compilers, editors and server kits – how will a young developer approach systems like Delphi?

I really want Delphi to survive and I want the object pascal language, be it Smart Pascal, FPC or Delphi or Oxygene; I want it to thrive. I want young programmers to see and experience how rich and beautiful object pascal is and how much it can do for them; and also how much they can deliver through that language.

But how can you even hope to persuade a young man or woman who makes less than $800 a month to fork out $3000 for a development system all their friends call “old and outdated”?

AppMethod is cool. It’s cheap, its affordable and students and hobbyist programmers can pick it up. It’s still a bit pricey compared to Smart Mobile Studio, but I hope Embarcadero makes enough money to keep going.

Last pondering

Smart Mobile Studio is probably more in tune with the new reality, since the kids growing up now are in fact growing up with “the cloud” as their foundation. Remember we grew up with commodore 64, Atari and those kind of things. Our children are growing up with cloud servers, JavaScript powered phones (Mozilla phone), Linux and the open source movement.

Perhaps I should just forget trying to make sense of their thinking. Trying to enumerate all the technological changes I have gone through from childhood to now is exhausting. I tried to tell my son what a modem was and how we connected to the internet no longer than 15 years ago — he just looked at me with big eyes and went “Dad. Please. Its ancient history”. And my daughter found a cassette tape and could not imagine what it was. She thought it was scotch tape 🙂

It’s just so weird realizing that my kids have no idea what a cassette tape is and will never have first hand experience of a modem!

I guess we all play our part.

My part is to try to get object pascal kicking and screaming onto the cloud. I am content with that role and think it’s a privilege to even be mentioned in the history of object pascal. But a future based on scripting? I sure hope not!

What are the kids using?

When it comes to languages, I can honestly say that the official list is wrong. Dead wrong. One language may have more source online that others, but that doesnt mean it’s less used. It depends completely on what group of people use it and what it’s used for. A language used primarily for commercial applications will by nature have less code in the public domain than a language which is free, open-source and generally available.

This is the case we see with Delphi. There are probably hundreds of thousands of companies using Delphi in the world, but they use Delphi to produce closed-source products. As such their code never leaves the house (so to speak) and you wont find it on github, sourceforge or google code.

But having talking to probably hundreds of teenagers coding lately, here is my general impression, in order of magnitude

  • JavaScript
  • Php
  • Python
  • Ruby
  • Swift
  • C# and dot net
  • C script
  • Erlang and friends

Of native languages the list havent really changed that much over the years:

  • C++
  • C
  • Objective C
  • Object Pascal

The javascript thing is the one to watch. Not just because that’s where I’ve invested my time and money, but because no other language is seeing anything near the amount of attention JS is getting. Not even close. And the two basic platforms is the browser, which for kids is regarded as the operative system itself (conceptually, not factually ofcourse). The browser IS where you experience computing and connect to the world.

The second aspect and one I find very exciting myself, is the nodeJS side of things. Here we are seeing a tremendous growth compared to other technology. And the reason is exactly because it’s connected to the first-hand experience people have. Those who master the browser and the DOM will eventually be able to reach customers and create systems which are platform independent, international and dynamic.

Do we have anything to learn from this? Bucket loads! But we should never lose sight of the fact that we also have much to teach.

And with that my pondering stops for today 🙂

In defense of Howard Scott Warshaw

April 23, 2015 1 comment

Howard Scott Warshaw was one of the lead programmers for Atari back in the eighties. While I can’t say I have followed his early career, at least not as closely as my generations’ heroes like Peter Molyneux or Sid Meyer, I knew like most people that Howard was responsible for the so-called “worst game ever”. Of that was the rumor anyways, which I first heard back in the nineties or something.

The myth goes that the 1982 E.T game was so bad, that Atari actually dumped millions of returned cartridges out in the dessert somewhere in an attempt to cover up the failure. It’s turned into an X-Files type operation where the game sucked so much, that the financial losses ended up killing the once mighty entertainment giant Atari.

Howard and Steven Spielberg, roughly  6 weeks before deadline

Howard and Steven Spielberg, roughly 6 weeks before deadline

Being a programmer myself I know how much it can hurt when you have worked for months on something, only to have 2-3 individuals tear it apart publicly (which in this case represents a tiny forum, way out in the suburbs of cyberspace). I can only imagine what it would be like to not only get an impossible project like the E.T game dumped in your lap, with a deadline of five weeks. And please remember guys, this is hand-written 8 bit machine code running on a now ancient piece of hardware.

The urban legend from hell

There are variations to the myth of course, like with all urban legends. In later years Howard is said to have gone to Commodore shortly after, implying that he was actually a spy of sorts, destined to kill Atari so that Commodore could make its way into the market. Which is utter rubbish because these companies were, at that time, galaxies apart. Commodore was never a big hit in the US, it struck root primarily in England and Europe. Particularly in scandinavia. In the US Amiga machines were primarily used for video production and television. It never really caught the public eye. So a programmer would be less likely to want to work for Commodore than Atari.

Raymond Kassar

Raymond Kassar

Add to this the fact that Howard was actually never again able to get a job as a programmer due to the myth, should be enough to dismiss this rumor as pure urban legend.

I mean, just imagine it: How would you feel if every single person on the planet was told that your code was the worst ever written or published? Not on some minuscule forum where you at least can defend yourself or just fix the bugs as they are reported. No, we are talking universally across the globe for thirty years !

It just makes me so angry and sad for what truly is one of the best programmers Atari ever had.

Was E.T really that bad?

I have never played the game myself, but I have seen plenty of you-tube reviews and gameplay. And having been an avid technologist since I was in high-school I can honestly say that this is not the worst game of all time. Far from it. I have played thousands of games in my time, from the green-mesh that was ZX-Spectrum, through Commodore VIC-20, 64, 128 and all the way up to Amiga, PC and lately, an overpriced iMac, iPhone and iPad.

The E.T game is now a highly priced collectors item

The E.T game is now a highly priced collectors item

I also own nearly every console known to mankind, missing only the Nintendo Gamecube and the Philips 3DO in my collection. So as far as games go, I am fairly confident that I have enough experience and insight to make a fair judgement. And if E.T was the worst game, I for one would not lie about it.

But let’s look at the system we are dealing with here first.

The Atari game console that Howard worked on was the Atari-2600. This is a system which in terms of features is somewhere along the lines of a Commodore 64. Just to place the hardware and capabilities in some sort of context. All games were hand written in machine-code, a task which by today’s standards is applaudable in itself. There were no C compilers, no Turbo Pascal and certainly no Delphi, Smart Mobile Studio or SDL libraries.

The Atari 2600, over 30 years old

The Atari 2600, over 30 years old

Developers essentially had a primitive text-editor, less evolved than even the most low-level linux command-line variation (which I must admit that I detest), and that was it. You punched in machine code and compiled with a second program. And there was no multi-tasking remember, so you had to quit the editor to compile. Just imagine how fun it was when a typo was present in line 26000 or something. Back into the editor, fix, save, exit – and try to compile again.

This is just to place the work in some form of context, so the reader get’s an idea of what being a programmer in the late 70’s early 80’s was like.

Now back to E-T and the whole “worst game” thing.

First of all, turns out that Howard had only successes up until E.T came along. Most of his games, especially the smash hit “Yar’s revenge” sold millions of copies and were immensely popular; making truckloads of cash for Atari. So Howard is absolutely not a bad coder. Quite the opposite, he was a highly skilled computer engineer; top of his class.

Yars Revenge was a smash hit and sold by the millions

Yars Revenge was a smash hit and sold by the millions

The E.T project was essentially a task thrown in his lap by management, who for some reason had managed to muscle the rights to E.T from Steven Spielberg personally. So Howard got the great honor of writing a complete self-contained gaming world in just five weeks. That is insane by any standards, and no matter how good you are at coding – five weeks is just madness. Even a small title could not be completed in that time, let alone a ROM image trying to capture the essence of a movie success like E.T.

And E.T was huge. If you think Star-Wars is big and all the commercialism around it is awesome, well with E.T you can triple that. So if you released all 3 initial star-wars movies at the same time, then you will have a good idea of how big E.T actually was.

You could hardly walk into a mall or store without some piece of E.T merchandise being offered. From posters to puppets, pencil cases, nap-sacks, bed-sheets, lamps, T-shirts (I loved mine to death and actually sold my BB gun just to buy the T-Shirt), shoes — everything which could be stamped with an E.T image or name was branded and sold. It was a billion dollar orchestration on a global scale.

So. Can you imagine the pressure and commercial anticipation for the computer game? The world was in a E.T frenzy, and every child in the western hemisphere was counting down for christmas, hoping to find the game under the tree.

The blame game

I think it’s so sad for Howard that people still talk about E.T as “the worst game of all time”. It’s worse than sad, it’s almost heartbreaking – even though I have never met the man.

It’s simply not true. E.T is not the worst game at all. From what I’ve seen (and I watched two whole reviews of the game) it’s absolutely not deserving of such a title. And I know this because I lived with the alternatives. Hell I had a ton of C64 games on Turbo-Tape which just sucked the marrow from your bones every time. The way it worked back then was that you could get bootleg games on tape. Normal music cassettes. That was how games for the Commodore 64, Spectrum and all those early “home computer kits” were distributed and sold.

Howard at his developer station at home

Howard at his developer station

You had a tape recorder hooked up to your computer, and the analog sounds from the casettes were transformed into digital patterns (data). If you ever had a PC in the 90’s you most likely remember the strange sounds it made when connecting to the internet? Well, that sound is the analog version of digital data. And that technology has only recently been replaced by fiber-optics. In some parts of the world modems are still used, like south america, Africa and regions of the middle-east.

Cut from CG magazine

Cut from CG magazine

Anyways, hackers existed back then as well and you could get bootleg versions of games and programs in compressed form (a bit like winzip or rar in our age) using a packer called Turbo. Turbo allowed you to stuff 10 games into the space of a single, un-compressed game. So what we did was put as many as 50 games on a 60 minute tape. These tapes were called “Turbo Tape’s”.

You would not believe some of the games that were sold for these computers; computers which were en-par with and better than the Atari’s 2600. And judging by what I’ve seen of E.T’s gameplay, it’s a much higher quality production than the early Commodore offerings I enjoyed as a child growing up in the riches country in the world: Norway.

So whenever someone says that E.T is the worst game ever made — just tell them that it’s not true. It’s a stupid urban legend that has practically destroyed a very accomplished programmer’s career and haunted him for 30 years. It’s a total lie and any gamer or programmer with half a conscience intact should stamp the myth out utterly.

Atari as a company was massive, with thousands of employees and hundreds of programmers. So the myth that E.T sucked so much that it toppled an entire industry is a joke at best. And what a complete disaster for Howard which until recently have been carrying this label around, unable to get even a clerical job in the computer game industry because of it. People dont care that he was in fact one of the best coders at Atari and that all his games sold millions of copies. They all just remember him through the E.T myth. It has been a clear case of character assassination from day one.

From what my reading has availed, Howard had re-invented himself and is now a “silicon valley head doctor”. It makes sense to have a programmer who speaks geek fluently to also be a doctor. And considering what he’s been through thanks to this stupid myth, he no doubt have a lot of wisdom to share with stressed out programmers who need help to deal with the problems we all face in life. A lesser man would have thrown himself in front of the metro for carrying such a label, but not Howard. A testament to his character and ability to find solutions.

A global apology

Howard Scott Warshaw

Howard Scott Warshaw, modern photo

The gaming community at large owes Howard an apology. Especially teenagers who have absolutely no insight into what software development is, nor would they have the skill or intelligence to produce anything like what Howard did back then. Even if they worked for years on it, they would not be able to re-produce what Howard did in just five weeks.

Nothing provokes me more than a 15-year-old kid thrashing stuff he doesn’t even know how works. He sits there with his X-Box or PSX4 and acts like he – based on his wast experience – had the right to thrash talk anything and everyone. Youth is wasted on the young plato once wrote, and no where is it more evident than in the mentality of spoiled western teenagers.

In all fairness the Kassar family and even Warner Bros themselves should write a huge check for Howard; for damages endured over a period of 30 odd years. It must have been practical to have a scape goat to blame the results of poor business decisions on; but eventually the truth comes out.

I also hope Howard one day receives the recognition he so deeply deserves, not for the five-week marathon that he incredibly enough delivered on — but for all the games he built prior to that, and for the fact that he was a pioneer. No one had done these things before. There were no books on coding games or courses you could take. These guys at Atari were the first to venture into a purely abstract science expressed through electronics; And they went in there armed only with their own ideas and ability to solve problems.

Well Howard, I can’t give you a huge check, nor can I give you an award — except to say that I will do my best to stamp out this lie which has haunted you for so many years. And I hope others who read this does the same.

Facts unearthed

Turns out that a movie about this was made a year or two back, called “Atari:Game over” which deals with the subject directly. In the movie they film as the graveyard where the so-claimed millions of games were burried, in fact contained very little E.T games. Instead some of the biggest Atari sellers were buried out there.

So what has been called a coverup and scandal, was nothing more than Atari cleaning out their storage space. No doubt to save money. Yet it ended up as a myth that killed the career of an excellent and innocent developer.

Here is a link to the movie “Atari: Game over” which can now be seen on NetFlix.

Howard at the excavation site, digging up E.T

Howard at the excavation site, digging up E.T from the dessert

Smart Mobile ‘retrogaming’ cloud services

April 19, 2015 1 comment

Im getting older. It’s with shock I have reached the age of 41 (!) In my sons eyes I am already the proverbial dinosaur. But in my own mind it was only yesterday I ran around with my friends, Amiga in nap-sack, on the way to some copy-party or gathering of Amiga enthusiasts, coders and gamers.

Sexy, compact and extremely fast! Amiga OS

Sexy, compact and extremely fast! Amiga

You may be wondering what all of this has to do with Smart Mobile Studio, cloud computing and object pascal. The answer is: everything. Because the Amiga computer was the machine which started all of this. In fact every project I have loved working on my entire life began on the Amiga. The reason I now live as a programmer is because of the Amiga. The reason I became who I am and live where I live, is because of the Amiga. And the reason I work where I do, and know what I know – is yet again because of the Amiga.

Trying to emphasis the impact the Amiga has had on hundreds of thousands of kids during the 80’s and 90’s is almost impossible. It’s like trying to explain the impact the moon landing had, or the cold war (we share a border with Russia, so that was fun). To be blunt: The Amiga has shaped my life more than any other person, education or “thing”.

The IOT phenomenon is about to emerge, so if you wanted a wink that a revolution is about to happen — this is it. Your chance to capitalize and make money is NOW.

Sadly I was to young to realize any of my ideas back then, and the hardware was not even close to deliver them. This is why the death of Amiga was so heartbreaking to a whole generation. Because the Amiga was the platform that gave us everything, yet it was cut down in it’s prime due to sloppy, greedy and outright insane management decisions. The entire IT market and reality of computing for the entire world would have looked very different had the Amiga realized it’s potential. Windows and OS X has only recently managed to catch up with the Amiga operative system. And we are talking about a machine which went out of production 20 years ago (!). It was way beyond anything Microsoft or Apple cooked up in their labs. We enjoyed a responsive and fast multitasking desktop, high-speed games and graphics and fantastic soundtracks – 15 years before the PC (fifteen years! That’s a whole “growing up” phase).

The amiga also had VR equipment more than 18 years ago. So yeah, it was a personal disaster for a whole generation when Commodore went bankrupt. It pushed computing back to the stone age. Could you imagine having to throw away your modern computer and be forced to buy a 15 year old piece of shit instead? Being told by people who know jack shit about the mac or pc you own today, that their old shabby system is better — when you in fact have tried future technology and used it for years, knowing full well that what they say is not true? Well, that was our experience. Having to pay money to get a 486 after having lived with an Amiga 1200/68040 CPU for years was just insane. It was like trading in your iPhone for a 1996 Nokia, or your Tessla car for a 1980 Fiat.

So indeed; we had so much more than kids today have. The experience of connecting your modem up to your dad’s phone, connecting to a BBS on the other side of the world, logging in and talking to people, swapping games, documents and whatnot — take a close look at the underlying technology there and what you see is the seed of cloud-computing.

A BBS functioned as a file-sharing service. So when you connected to the BBS, the files, games etc. you placed in the public folder was immediately shared with the others. And they all went through the server first, which typically picked up whole files first.

The Amiga was a lot more than just a games machine, it was way  ahead of both Windows and OS X for a decade

The Amiga was a lot more than just a games machine, it was way ahead of both Windows and OS X for roughly 15 years. So for 15 years we had a full multitasking desktop.

Now, going from that – to a reality of mainframes, thin clients, abstracted filesystems and remote data storage (or even better: dispersed data storage, where chunks of data can be stored anywhere on the planet and re-assembed when you need it) — all of this saw the light of day on the Amiga. In fact the second webbrowser ever written (the first was naturally on a unix machine) was written on the Amiga.

A fully working US produced Amiga 500, re-built and fixed by me this weekend. It took 2 days to get it working, but it's worth it!

A fully working US produced Amiga 500, re-built and fixed by me this weekend. It took 2 days to get it working, but it’s worth it!

But for me personally: did you know that the first programming language I wrote was called “concept basic”? It was written in assembler and blitzbasic on the Amiga. So the idea of programming languages, delivering a fun system that people love — it comes directly from my Amiga days. I would never have created Smart Mobile Studio or connected with the other people of the team had I never owned an Amiga.

Blitzbasic and Amos

Have you ever thought about the people who inspired your childhood? Not your mother and father, but all those people who – behind the scenes, did something which had a huge impact on your life? I have thought about that many times. And I believe hundreds and thousands of teenagers back then was touched by two titles especially, written by two near iconic Amiga personalities.

The first is Marc Sibly who gave us BlitzBasic, which was on the Amiga the closest thing to Turbo Pascal or low-level Delphi as you could get. You could write assembler side-by-side with fast basic, and the compiler gave you a single executable which ran at extreme speeds. Even die-hard assembler coders took their hat of to Marc for his invention.

Games like Worms and Lemmings were coded in BlitzBasic  2

Games like Worms and Lemmings were coded in BlitzBasic 2

The other title which enabled a world of children to learn programming and be creative, is Francois Lionet. I have been fortunate enough to talk with him online, where I also expressed my gratitude for Amos Basic. It’s really sad that so few Amiga users have done this, because both Francois and Marc deserves to be recognized.

Amos basic was the multimedia basic par excellence

Amos basic was the multimedia basic par excellence

Thanks to these two people and programming tools – hundreds of thousands of kids became professional programmers.

I cannot express enough just how fun it was to grow up with BlitzBasic and Amos basic. Every day before I went to school I would spend an hour coding. Slowly learning trick by trick. Without the inspiration of these two IDE and compilers, I have no idea what I would be working as right now. But I doubt I would be as happy as I am, or have such a rich intellectual life as I enjoy.

Smart Mobile Studio

What I really want is to re-create that feeling for others. I want people to start Smart Mobile Studio and feel that they can make anything. Be it games, mobile applications or cloud services. I realize of-course that the majority of people using Smart are grown men, but with the student program and a few plans we have — odds are we will be able to reach teenagers who want to master programming. Just like Marc and Francois did for us.

Early variation of Smart Mobile Studio

Early variation of Smart Mobile Studio

So that is a huge driving force in what I do and my work in programming language research

Raspberry PI

What is a cloud? Well it’s not just storage. Even though that is the first service people think about. So dropbox is not really a cloud service just because it allows seamless backup and re-distribution of data. But it is indeed one of the services cloud delivers.

No, what cloud is – is a very, very old idea. The idea that you log into a huge system, allocate computer time (just like on star-trek) and then work on your task is ancient. It goes back even before the Amiga to the huge IBM mainframes of the fifties, sixties and seventies.

The commodore mainframe, an ancient idea

The commodore mainframe, an ancient idea

The fun part is that a single $35 Raspberry PI 2 contains more computing power than the entire US government combined in the nineteen sixties. Just think about that for a moment.

But it should also mean that we have something to learn here, or an opportunity to explore and do things our parents never even dreamed about.

And this is where the Raspberry PI cloud system comes in. I have been coding this for a while now, and it still requires work, but when it’s done – you will be able to run your very own cloud using a single or multiple Raspberry PI’s. An the pricetag? For a measily $140 you can now own a 16 core cloud setup. Perfect for writing cloud software, which (let’s face it) the world is heading.

Smart Cloud

Cloud storage, coming to a smart RTL near you in the future

Cloud storage, coming to a smart RTL near you in the future

So what exactly is this cloud thing? Well, in short it allows you to install cloud resident applications. Meaning applications which live in the cloud, store data in the cloud, and which conforms to the laws of the cloud reality.

This means that you will be able to develop, test, maintain and deploy your own cloud solutions directly on your own mini-cluster at home. When your service is complete, tested and validated — you simply upload the whole system (a zip file) to Amazon or Azure. Now your system is “live” and can be reached by millions of potential customers though mobile phones, pads, smart-tv’s, tabs and computers of any size and form.

The IOT phenomenon is about to emerge, so if you wanted a wink that a revolution is about to happen — this is it. Your chance to capitalize and make money is NOW. If you wait a year, the window will be lost and you will have to wait for the “next big thing”.

Retro computing taken to the extreme

The first service I am going to make, besides the professional tools you need to write kick-ass cloud software, is the ultimate retro gaming platform in the universe. You may have heard of RetroPI, WinUAE and all those emulators which plays Nintendo, Amiga, Playstation and Mame games (NEO GEO) ? Imagine running all of these on a cluster.

Thousands of classical titles at your fingertips

Thousands of classical titles at your fingertips

Imagine being able to easily upload and download games via our Smart Mobile Studio nodeJS services (which you will get when you buy it, to run in your own home). And imagine (drumroll) being able to start and play those games from anywhere in the world. All you need is a browser, and the emulated screen will be transported to the browser in real-time.

With your cluster running at home, you can be in any hotel in the world and access thousands of games, movies and music. And the good part? It’s all written in Smart Mobile Studio, using the SmartSDI daemon interface (daemon is the same as service on linux).

Look out! 1990 is about to hit your system, like a ton of PI's

Look out! 1990 is about to hit your system, like a ton of PI’s

Sounds hard? Well not really. The cool thing about X, the windowing manager on Linux, is the idea of remote desktop session. So connecting and getting the desktop pixels is there from scratch. The rest is pure RPC service architecture, a handfull of scripts – and cluster software, allowing you to make use of all 16 ARM cores for tasks.

Well, stay tuned!

Smart Mobile Studio nodejs hardware platform

April 18, 2015 Leave a comment

I am proud to announce that my research into nodeJS and inexpensive hardware has resulted in the Smart Mobile Studio server platform, which is an inexpensive but highly usable linux setup designed to run on the Raspberry PI model B.

When the system is ready you will be able to download a Linux disk-image from http://www.smartmobilestudio.com for use with your own Raspberry PI 2. I am also talking to a Norwegian supplier about selling ready-to-use Raspberry PI 2’s with SmartSDI (Smart Software Distribution interface).

Working with SmartSDI

SmartSDI is a Linux executable written in FreePascal which simplifies moving files between the Raspberry PI and your Windows machine. The system can interface with Smart Mobile Studio directly, meaning that when the IDE obtains support for SmartSDI, it can automatically transport the compiled files to the Raspberry PI, install it into the nodeJS service stack — and you can test the application directly: either through your browser, your mobile phone or iPad/tablet.

It also makes it a snap to write your client applications, because once the server has been installed though SmartSDI, the client can connect and talk to it using the same interfaces as Amazon and Azure cloud services.

SmartSDI is also a lot more. It allows you to write, test and work closely with your Smart nodeJS services. Doing this on a dedicated “mini-computer” before you deploy to the cloud can mean the difference between success and failure.

The Raspberry PI2 image comes complete with nodeJS, mySQL and a host of typical nodeJS libraries and extensions. The goal is to provide you with an inexpensive, fully functional and convenient run-time environment for your cloud software.

The hardware runs on 5v only, which makes it suitable for 24/7 operation. It’s extremely cost effective at $35. Making Smart Mobile Studio the least expensive development platform for it’s gentre in the world. Embarcadero is 100 times more expensive for mobile and cloud work, and you get nothing we dont deliver. Even if you bought a 10 piece nodeJS cluster you would still have $2000 to spare.

The question should be — is Delphi 100 times better at modern mobile development?

From idea to production

With this platform, Smart Mobile Studio delivers a complete development path – from your idea to the finished product. The cloud based mobile application model can seem alien to many Delphi programmers, but it’s actually involves less work and more fun than native programming.

The cloud platform is likewise inexpensive, easy to use and easy to deploy to once understand it.

But stress testing your services, throwing deliberate exceptions and problems — which is the only way to be sure your program can deal with real-life problems, is expensive and time-consuming if done straight on the cloud node or your local PC.

This is where SmartSDI comes in. It comes with everything ready and working. Want to use mySQL in your cloud solution? Just use a mySQL editor and connect to the Raspberry PI to create your database. Now go back into Smart Mobile Studio and start using the mySQL drivers to talk with it.

When it all works as expected, your cloud solution is ready for deployment! A wizard will help you through the steps of uploading your cloud solution to your service provider (Amazon, Azure) and it’s up and running in minutes (!)

With the server in place, you package your client application with phonegap, and voila — you are ready for the marketplace! With Android, iOS, Blackberry and Microsoft mobile support ready to rock!

Moving to RiouxSVN

April 17, 2015 6 comments

In order to not mix the eggs or dot the teeth (and so on), I have decided to move my personal code to RiouxSVN.

This includes my repository of Smart Mobile Studio code and component sets,  including the cool new Database Grid, DB framework and DB aware controls.

Almost complete DB grid for SMS

Almost complete DB grid for SMS

The move will take place sometime during this weekend. So add this repo to your SVN subscriptions. Everyone is allowed to read from the repository. Updates and changes to the repo should be submitted to me, or on a temporary git repository so I can import the changes.

https://svn.riouxsvn.com/smartpacks

When to use

Ordinary rules apply. This means that you should never use code you download while the branch is in development mode and use that in a commercial or critical product. For that, use the repository browser and fetch a stable version.

Typically a repo history will look somthing like:

DATE ---- VERSION -- COMMENT
26.09.2015 0.5.2.1 more fixes and stuff
29.09.2015 0.5.2.0 STABLE
26.09.2015 0.5.1.7 more fixes and stuff
21.09.2015 0.5.1.2 Fixed this and that

In the above example, grab the one marked “STABLE” for productions. But for testing out the latest stuff, just keep the repo up-to-date 🙂

Node-Sega, this is cool!

April 14, 2015 Leave a comment

It was in the year of our lord 2015, when a norwegian brilliant scientist, dirsturbingly norwegian, but brilliant non the less – came to create the most awesome nodeJS server the world had ever seen.

And he putteth not one, ney, nor two, ney, nor three, ney — but four Raspberry PIes which he ordereth from the gloomy land called brittania through fed-ex, or fed-up or whatever the lord callest them sad men in browish cars delvering goods.

NodeSega

What do you get when you marry Raspberry PI (four of them), a Sega MegaDrive II, nodeJS and a whole afternoon of free time? Well if you are around me you will get the all singing, all spanking – Node-Sega MegaJS (ta-da!).

Ok serious: I ordered a Sega MegaDrive II from AliExpress, which ships good from China. I didnt expect much from this product because, let’s face it – they do sell a lot of rubbish on that website; but since the verison II of the megadrive never came out up here in Norway — what did I have to loose? It cost something like $30 or so – with shipping (!)

Daddy's new toy -- it goes with the 16 other collectables I own

Daddy’s new toy — it goes with the 16 other collectables I own

Well, I get the sucker delivered and the first thing I find is a maelformed power socket. And to make it even more interesting its a 9 volt adapter. Not 6, not 8 or 12 – something normal that you may have around the house. Nope, a nine volt adapter.

I open the damn thing up and check, and the motherboard actually runs on 5 — which I just happen to have a ton of. So a quick modding and it’ working. Sort of. For 3 seconds until it goes up in smoke. They really dont make’em like they used to! I remember my US produced Amiga computer. I spilled coke over it, fall off a motorbike with it in my backpack, i even jumped into a pool once with my Amiga in the napsack — it didnt even glitch. You could set the bloody thing on fire and it would still boot up.

Wow, they really polled out all the stops for this one. $0.30 in parts?

Wow, they really polled out all the stops for this one. $0.30 in parts?

Old box, new tricks

So with a freshly “burnt out” Sega Megadrive at my disposal, what should a man do? But build a Raspberry PI cluster containing: Mame arcade game emulator, NodeJS web server interface for uploading and downloading MAME Roms. A dedicated PI for database work and a fallback server so nodeJS can spawn threads on a secondary machine.

So my trusty old, very new Sega megadrive will not end it’s days on the skip having come here all the way from china — instead it is being transformed into a supe sega! When sega machines talk about heroes they will whisper the name of the super-sega who went to Norway to become a most powerful sega in the universe. Mohahahaha…

Alas, this GPU is no more of use.. oh the horror

Alas, this GPU is no more of use.. oh the horror

Now to squeeze in 4 of these babies!

Now to squeeze in 4 of these babies!

I guess I dont need to tell you where this is heading right? I must admit it’s going to be so fun to do this mod. I can just imagine the face of my boss when he asks me to bring my nodeJS monster to work. And I bring a Sega megadrive, hook it into the network and watch everything light up 🙂

Still, it does need some work. There is a height difference I need to fix, also need two types of switches (reset and movable), a HDMI extender (short) a power-led extender and splitter. A USB splitter (it will have 16 USB ports!).

Now that’s a megadrive!

And what should we call this freepascal and Smart Mobile Studio powered cluster? Why Sonic ofcourse!

Sonic clustering

Sonic clustering

Why is the seganodeJS megadrive so sexy?

The megadrive chassis is just the perfect size to do a avant-garde mod using Raspberry PI. First of all because it has plenty of room, but also because of height and the position of power-in and video/sound-out match our goals — well, perfectly!

It turns out the HDMI-out and power-in socket on the RPI fits neatly. This means that you will have power-in and HDMI out exactly where similar sockets used to be. This is a fingertip-rule when doing mod’s. Always, always try to retro-fit new sockets and parts where the older versions were. It will save you so much time and headache later.

To demonstrate just how much space the Sega chassis gives us, consider this fab setup I have in mind:

4. diasy-chained Raspberry PI 2B
2. Re-chargable power banks
1. Terrabyte slim 2.5″ USB 3.0 storage
1. USB splitter (1 to 6) which will be exposed in the cartridge bay-door
1. Fully working reset button, safe shutdown due to power-banks
1. Fullt working shutdown (hard) button
1. 5v internal fan
4. mico-heat sinks to keep the CPU’s fresh
Assorted cables

You would never, ever get anything like this into a PSX1 or psx2. You would have to gut open your XBox 360 or something, because the PSX is utterly dominated by the CD-ROM and blueray “brick” inside.

Another thing: If you decide to place the first PI right at the back and re-cycle the old power-input holes, you are lining yourself up for a neat gadget, because: one of the cooler things about the RPI is that it’s perfectly happy getting it’s power from a USB connection. And since the RPI comes with 4 USB ports, thats 3 ports to power the other RPI’s with one spare port.

And you use that spare port with a USB splitter which gives you six USB 2.0 ports in return.
This gives you 6 + 9 = 16 fully functional USB ports available to your cluster (!)

Software setup

Since the RPI has become so famous around the world, plenty of software can be downloaded for it. This includes cluster software, home-cloud solutions and whatever you can imagine. But for my solution you dont really need that much.

The vanilla Noobs setup with Raspdebian is more than ok. Because the only thing you are going to do is to pick one of them to be head-honcho. And this linux box PI should provide the following:

  • DNS service
  • Firewall service
  • Internet provider for the other machine
  • Shared HW resources (e.g “printer”, “keyboard” etc)
  • 6 extended USB ports are shared out from this unit
  • Desktop service
  • Freepascal
  • NodeJS
  • Mame
  • Remote desktop access

What you want to do here is to first setup the linux system so that it works, then and only then do you install MAME with a boot menu — that way when you fire it up the system will boot into a menu of games, and you can use your joystick ($10 gamepad, sega lookalike on amazon) to scroll around and pick a game.

But, you also want to be able to access linux. So pressing ESC on a BT device or physically connected keyboard should break you out of the MAME cycle and boot X as normal.

The second machine

The second machine is the actual nodeJS server where you will be running most of your programs. A linux system can have a maximum of 1024 sockets in read/write mode at any given point (but thousands of allocated sockets waiting) so you want to dedicate a full RPI for this task.

  • Standard Raspbean install
  • Remote desktop access
  • NodeJS
  • network name “http”

The third machine is the boring RPI, namely the database. The setup is pretty much the same as the server, except this one should have mySQL running.

  • Standard Raspbean install
  • Remote desktop access
  • MySQL
  • network name “DATA”

The last and final machine is more popular, it’s the storage manager for the entire system. This machine will have all it’s USB ports used and connected to storage, which it shares openly with it’s own network. Since the network doesnt extent beyond the DNS and firewall, it’s all good for our little cluster.

You can also install samba and use it as a backup target for time-machine if you own a mac, or a backup target if you work exclusively with windows. So your Sega Raspberry nodeJS drive can become your most priced possession 🙂

Well — thats it for me today! I have a SEGA to assemble 🙂

CSS Builder Class, Smart Syntax

April 12, 2015 Leave a comment

In my last post I demonstrated just how flexible CSS can be when you start to automate it. Well, if you want to play around with this NOW as opposed to waiting for the next update, I have written down directions to do so here.

First you need the CSS class. This can be found in the QTX library which is hosted on Google Code (Click here to view the repository). Note: You dont need the whole library, just download the unit in the link and rename it and you’re good. Save the files in the libraries folder of Smart Mobile Studio (see the start button registration for Smart, there is a link to the RTL and Library folder).

Generating cool effects is now super easy

Generating cool effects is now super easy

Right. With the CSS class in your possession you now need the builder class. This is essentially a small class with keywords that, when used, generate CSS code according to the functions and when they are used. So if you do something wrong the CSS will come out wrong.

Here is the generator class so far:

unit darth.stylesheet;

//#############################################################################
//
//  DARTH COMPONENTS
//
//  Author:     Jon Lennart Aasenden
//  Copyright:  Jon Lennart Aasenden, all rights reserved
//
//#############################################################################

interface

uses
  System.Types,
  System.Colors,
  SmartCL.System;

type

  TDarthStyleSheet = Class(TObject)
  private
    FHandle:    THandle;
  protected
    function    getSheet:THandle;
    function    getRules:THandle;
    function    getCount:Integer;
    function    getItem(index:Integer):String;
  public
    Property    Sheet:THandle read getSheet;
    Property    Handle:THandle read FHandle;
    function    Add(aName:String;const aRules:String):String;overload;
    Procedure   Add(const aRuleText:String);overload;

    Property    Count:Integer read getCount;
    Property    Items[index:Integer]:String
                read getItem;

    class procedure addClassToElement(const aElement:THandle;const aName:String);
    class procedure removeClassFromElement(const aElement:THandle;const aName:String);
    class function  findClassInElement(const aElement:THandle;const aName:String):Boolean;

    Constructor Create;virtual;
    Destructor  Destroy;Override;
  End;


  TSuperStyle = static class
  public
    class function  EdgeRound(Size:Integer):String;overload;
    class function  EdgeRound(topleftP,toprightP,bottomleftP,
                    bottomrightP:Integer):String;overload;
    class function  EdgeTopaz:String;
    class function  EdgeAngaro:String;

    class function  AnimGlow(aFrom,aTo:TColor):String;

    class procedure AnimStart(Handle:TControlHandle;animName:String);

  end;


implementation

var
_sheet: TDarthStyleSheet;

function getStyleSheet:TDarthStyleSheet;
begin
  if _sheet=NIL then
  _sheet:=TDarthStyleSheet.Create;
  result:=_sheet;
end;

class procedure TSuperStyle.AnimStart(Handle:TControlHandle;animName:String);
begin
  animName:=animName.trim;
  if  (animname.length>0)
  and (handle) then
  begin
    Handle.style['-webkit-animation-name']:=animName;
    Handle.style['-webkit-animation-duration']:='2s';
    Handle.style['-webkit-animation-iteration-count']:='infinite';
  end;
end;

  type
  TCSS = class
  public
    Property  Text:String;
    function  KeyFrames:TCSS;
    function  From:TCSS;
    function  &To:TCSS;
    function  Enter:TCSS;
    function  Leave:TCSS;
    function  PercentOf(Value:Integer):TCSS;
    function  IntOf(Value:Integer):TCSS;
    function  ColorOf(Value:TColor):TCSS;
    function  &inc(Value:String):TCSS;
    function  CRLF:TCSS;
    function  OpenParam:TCSS;
    function  CloseParam:TCSS;
    function  Background:TCSS;
    function  BoxShadow(Left,Top,Right,Bottom:Integer):TCSS;overload;
    function  BoxShadow(Left,Top,Right,Bottom:Integer;
              Color:TColor):TCSS;overload;

    function  LinearGradientV(aFrom,aTo:TColor):TCSS;
    function  LinearGradientH(aFrom,aTo:TColor):TCSS;
    function  LinearGradientTL(aFrom,aTo:TColor):TCSS;
    function  LinearGradientTR(aFrom,aTo:TColor):TCSS;

    Function  BeginComplexGradient(Angle:Integer):TCSS;
    function  EndComplexGradient:TCSS;

    function  ColorPercent(PercentOf:Integer;Color:TColor):TCSS;

    function  LinearGradientAngle(aFrom,aTo:TColor;
              Const Angle:Float):TCSS;overload;

    function  LinearGradientAngle(Colors:Array of TColor;
              Const Angle:Float):TCSS;overload;

    function  AnimationName(name:String):TCSS;
    function  AnimationDuration(Secs,MSecs:Integer):TCSS;
    function  AnimationInfinite:TCSS;
  end;

function TCSS.KeyFrames:TCSS;
begin
  Text:=Text + '@-webkit-keyframes ';
  result:=self;
end;

function TCSS.CRLF:TCSS;
begin
  Text:=Text + #13;
  result:=self;
end;

function  TCSS.OpenParam:TCSS;
begin
  Text:=Text + ' (';
  result:=self;
end;

function  TCSS.CloseParam:TCSS;
begin
  Text:=Text + ') ';
  result:=self;
end;

function TCSS.&inc(Value:String):TCSS;
begin
  Text:=Text + value;
  result:=self;
end;

function TCSS.PercentOf(Value:Integer):TCSS;
begin
  Text:=Text + TInteger.EnsureRange(Value,0,100).toString + '% ';
  result:=self;
end;

function TCSS.IntOf(Value:Integer):TCSS;
begin
  Text:=Text + Value.toString + ' ';
  result:=self;
end;

function TCSS.ColorOf(Value:TColor):TCSS;
begin
  Text:=Text + ColorToStr(Value) + ' ';
  result:=self;
end;

function  TCSS.Enter:TCSS;
begin
  Text:=Text + '{' + #13#10;
  result:=self;
end;

function  TCSS.Leave:TCSS;
begin
  Text:=Text + '}' + #13#10;
  result:=self;
end;

function TCSS.From:TCSS;
begin
  Text:=Text + 'from ';
  result:=self;
end;

function TCSS.&To:TCSS;
begin
  Text:=Text + 'to ';
  result:=self;
end;

function TCSS.BoxShadow(Left,Top,Right,Bottom:Integer):TCSS;
begin
  Text:=Text + '-webkit-box-shadow: '
    + TInteger.ToPxStr(Left) + ' '
    + TInteger.ToPxStr(Top) + ' '
    + TInteger.ToPxStr(Right) + ' '
    + TInteger.ToPxStr(Bottom) + ';';
  result:=self;
end;

function TCSS.BoxShadow(Left,Top,Right,Bottom:Integer;Color:TColor):TCSS;
begin
  Text:=Text + '-webkit-box-shadow: '
    + TInteger.ToPxStr(Left) + ' '
    + TInteger.ToPxStr(Top) + ' '
    + TInteger.ToPxStr(Right) + ' '
    + TInteger.ToPxStr(Bottom) + ' '
    + ColorToWebStr(Color) + '; ';
  result:=self;
end;

function TCSS.Background:TCSS;
begin
  Text:=Text +'background:';
  result:=Self;
end;

function  TCSS.LinearGradientV(aFrom,aTo:TColor):TCSS;
begin
  Text:=Text + '-webkit-linear-gradient('
  + ColorToWebStr(aFrom) + ',' + ColorToWebStr(aTo) + ');';
  result:=Self;
end;

function  TCSS.LinearGradientH(aFrom,aTo:TColor):TCSS;
begin
  Text:=Text + '-webkit-linear-gradient(left,'
  + ColorToWebStr(aFrom) + ',' + ColorToWebStr(aTo) + ');';
  result:=Self;
end;

function TCSS.LinearGradientTL(aFrom,aTo:TColor):TCSS;
begin
  Text:=Text + '-webkit-linear-gradient(left top,'
  + ColorToWebStr(aFrom) + ',' + ColorToWebStr(aTo) + ');';
  result:=Self;
end;

function TCSS.LinearGradientTR(aFrom,aTo:TColor):TCSS;
begin
  Text:=Text + '-webkit-linear-gradient(right top,'
  + ColorToWebStr(aFrom) + ',' + ColorToWebStr(aTo) + ');';
  result:=Self;
end;

function TCSS.LinearGradientAngle(aFrom,aTo:TColor;Const Angle:Float):TCSS;
begin
  Text:=Text + '-webkit-linear-gradient(' + FloatToStr(Angle)
    + 'deg, ' + ColorToWebStr(aFrom) + ',' + ColorToWebStr(aTo) + ');';
  result:=Self;
end;

function TCSS.LinearGradientAngle(Colors:Array of TColor;Const Angle:Float):TCSS;
var
  x:  Integer;
begin
  Text:=Text + '-webkit-linear-gradient('
  + FloatToStr(Angle) + 'deg, ';
  for x:=0 to Colors.length-1 do
  begin
    Text:=Text + ColorToWebStr(Colors[x]);
    if x<Colors.length-1 then
    Text:=Text + ',';
  end;
  Text:=Text + ');';
  result:=Self;
end;

Function TCSS.BeginComplexGradient(Angle:Integer):TCSS;
begin
  Text:=Text + '-webkit-linear-gradient(' + FloatToStr(Angle) + 'deg,';
  result:=self;
end;

function TCSS.EndComplexGradient:TCSS;
begin
  Text:=Text + ');';
  result:=self;
end;

function TCSS.ColorPercent(PercentOf:Integer;Color:TColor):TCSS;
begin
  if Text[length(text)]='%' then
  Text:=Text + ',';

  Text:=Text + ColorToWebStr(Color) +  ' '
  + TInteger.EnsureRange(PercentOf,0,100).toString + '%';
  result:=self;
end;

function TCSS.AnimationName(name:String):TCSS;
begin
  Text:=Text + '-webkit-animation-name: ' + Name + ';' + #13#10;
  result:=self;
end;

function TCSS.AnimationDuration(Secs,MSecs:Integer):TCSS;
begin
  Text:=text + '-webkit-animation-duration: ' + IntToStr(Secs)
    + '.' + IntToStr(mSecs) + 's;' + #13#10;
  result:=self;
end;

function TCSS.AnimationInfinite:TCSS;
begin
  Text:=Text + '-webkit-animation-iteration-count: infinite;' + #13#10;
  result:=Self;
end;

class function  TSuperStyle.AnimGlow(aFrom,aTo:TColor):String;
var
  mStyles:  TDarthStyleSheet;
  mWriter:  TCSS;
begin
  mStyles:=getStyleSheet;
  if mStyles<>NIL then
  Begin
    result:=w3_GetUniqueObjId;
    mWriter:=TCSS.Create;
    try
      mWriter
        .KeyFrames.inc(result + ' ')
        .Enter
          .from
          .enter.BoxShadow(0,0,0,0).leave.CRLF

          .PercentOf(50)
          .Enter.boxShadow(0,0,12,0,aTo).leave.CRLF

          .to
          .enter.BoxShadow(0,0,0,0).leave.CRLF
        .Leave .CRLF;

        writeln(mWriter.text);
        mStyles.Add(mWriter.Text);
        mWriter.text:='';

        mWriter
          .inc('.' + result + '_player ')
          .enter
            .AnimationName(result)
            .AnimationDuration(2,0)
            .AnimationInfinite
          .leave;
        mStyles.add(mWriter.text);
    finally
      mWriter.free;
    end;
    result:=result + '_player';
  end;
end;

class function TSuperStyle.EdgeRound(topleftP,toprightP,bottomleftP,
      bottomrightP:Integer):String;
var
  mStyles:  TDarthStyleSheet;
begin
  mStyles:=getStyleSheet;
  if mStyles<>NIL then
  Begin
    var mText:='border-radius:';
    if topleftP>0 then
    mText := mText + TInteger.ToPxStr(TInteger.ensureRange(topLeftP,0,100));

    if toprightP>0 then
    mText := mText + ' ' + TInteger.ToPxStr(TInteger.ensureRange(toprightP,0,100));

    if bottomRightP>0 then
    mText := mText + ' ' +TInteger.ToPxStr(TInteger.ensureRange(bottomRightP,0,100));

    if bottomLeftP>0 then
    mText := mText + ' ' +TInteger.ToPxStr(TInteger.ensureRange(bottomLeftP,0,100)) + ';';

    result:=mStyles.Add(result,mText);
  end;
end;

class function TSuperStyle.EdgeRound(Size:Integer):String;
var
  mStyles:  TDarthStyleSheet;
begin
  mStyles:=getStyleSheet;
  if mStyles<>NIL then
  result:=mStyles.Add(result,'border-radius: ' + TInteger.ToPxStr(Size));
end;

class function TSuperStyle.EdgeTopaz:String;
begin
  result:=TSuperStyle.EdgeRound(15,50,0,0);
end;

class function TSuperStyle.EdgeAngaro:String;
begin
  result:=TSuperStyle.EdgeRound(15,50,30,0);
end;

//############################################################################
// TDarthStyleSheet
//############################################################################

Constructor TDarthStyleSheet.Create;
var
  mDocument: THandle;
begin
  inherited Create;
  mDocument:=BrowserAPI.document;
  FHandle:=mDocument.createElement('style');
  FHandle.type := 'text/css';
  mDocument.getElementsByTagName('head')[0].appendChild(FHandle);
end;

Destructor TDarthStyleSheet.Destroy;
Begin
  if (FHandle) then
  FHandle.parentNode.removeChild(FHandle);
  FHandle:=null;
  Inherited;
end;

function TDarthStyleSheet.getCount:Integer;
Begin
  if (FHandle) then
  result:=getRules.length else
  result:=0;
end;

function TDarthStyleSheet.getItem(index:Integer):String;
Begin
  if (FHandle) then
  result:=getRules[index].cssText
end;

(* Takes height for differences between webkit, moz and IE *)
function TDarthStyleSheet.getRules:THandle;
var
  xRef: THandle;
Begin
  if (FHandle) then
  begin
    xRef:=getSheet;
    asm
      @result = (@xRef).cssRules || (@xRef).rules;
    end;
  end;
end;

(* Takes height for differences between webkit, moz and IE *)
function TDarthStyleSheet.getSheet:THandle;
var
  xRef: THandle;
Begin
  if (FHandle) then
  begin
    xRef:=FHandle;
    asm
      @result = (@xRef).styleSheet || (@xRef).sheet;
    end;
  end;
end;

class procedure TDarthStyleSheet.addClassToElement(const aElement:THandle;
      const aName:String);
Begin
 w3_AddClass( aElement,aName);
end;

class procedure TDarthStyleSheet.removeClassFromElement(const aElement:THandle;
      const aName:String);
Begin
  w3_RemoveClass(aElement,aName);
end;

class function  TDarthStyleSheet.findClassInElement(const aElement:THandle;
      const aName:String):Boolean;
Begin
  result:=w3_hasClass(aElement,aName);
end;

Procedure TDarthStyleSheet.Add(const aRuleText:String);
var
  mDocument: THandle;
  mSheet: THandle;
Begin
  mDocument:=BrowserAPI.document;
  if (FHandle) then
  Begin
    mSheet:=getSheet;
    if not (mSheet.insertRule) then
    mSheet.addRule(aRuleText) else
    mSheet.insertRule(aRuleText,0);
  end;
end;

function TDarthStyleSheet.Add(aName:String;const aRules:String):String;
var
  mDocument: THandle;
  mSheet: THandle;
Begin
  aName:=trim(aName);
  if length(aName)=0 then
  aName:=w3_GetUniqueObjId;

  mDocument:=BrowserAPI.document;
  if (FHandle) then
  Begin
    mSheet:=getSheet;
    if not (mSheet.insertRule) then
    mSheet.addRule('.' + aName,aRules) else
    mSheet.insertRule('.' + aName + '{' + aRules + '}',0);
  end;

  result:=aName;
end;

end.

Now inside the AnimGlow function in TSuperClass, you will notice that we have pretty much gone overboard with linear-gradients. Just ignore this for now, we will be dealing with each section one by one.

HTML5 valentines card

HTML5 valentines card, pure animated CSS

[coded by me back in 2012 to my GF]

But first, let’s get to know the commands of TCC. We start with the simple 1:1 type commands and leave the more advanced for later.

TCSS functions

  • Enter = {
  • Leave = }
  • To = to
  • From = from
  • PercentOf(Value) = Value%
  • IntOf(Value) = Value
  • ColorOf(Color) = $hex-color-value
  • inc(string) = add plain text to buffer
  • CRLF = carriage return and linefeed (#13#10, or just #13)
  • OpenParam = (
  • CloseParam = )
  • ColorPercent(Value,Color) = $hex-color-value %value,

The above functions map to simple CSS constructs. For instance, to generate a small JSON object you would write:

 .enter .inc(&amp;quot;value = 12;&amp;quot;) .leave 

And if you check the “text” property you find this:

  {
    value = 12;
  }

These types of functions are not so much time helpers as they are space helpers. It’s the other, high level functions which greatly simplify css generation.

For instance, a complex multi-colored, percentage-divided angular linear-gradient (phew!) can now be reduced to this:

.beginComplexGradient(80)
  .ColorPercent(10,clRed)
  .colorPercent(40,clBlue)
  .colorPercent(50,clWhite)
.endComplexGradient

This results in a variation of this (more compact):

background: -webkit-linear-gradient
   (
     80deg,
     #ff0000 10%,
     #0000ff 40%,
     #ffffff 50%
   );

When you start to build ever more complex shapes (this class is not yet done, not by a longshot) the generated CSS will become more and more complex, meaning that you save more and more time and headache; yet your code remain easy to read and maintain. At least once you know the basics of the class and what is going on.

Odd syntax

If you think the syntax is a bit odd then yes, we are using a fairly modern tecnique – where all functions return a reference to its “self”. This means you can call function after function in the same object without line-break.

At the same time we add data to an internal property (in this case cleverly called “text”). When all is done and ready we collect the output from Text and voila — we have our magic CSS style(s) and animations.

I will keep you all updated on this development. It will not be included in the next update of Smart Mobile Studio, because — well, it’s just a little snippet I’ve been playing with for half an hour. But it may make the next update after that, when it’s more mature and advanced.

Until then, play around with it and add more CSS wrappers (!)

Creating CSS animations at runtime

April 11, 2015 2 comments

Smart Mobile Studio has a lot of cool features. For instance, did you know that SMS automatically maps your pascal class-names to your css class-names? It quite clever and very effective.

In the example above we animate a glowing, red 12px cloud around the button. It slowly fades into full red, then it fades back out into nothingness.

But despite all the tricks and power in Smart Mobile Studio, a programming system is only as good as its biggest weakness. And while it sounds like a paradox, CSS is Smart’s weakness and strength.

Power to CSS

CSS is fantastic once you really understand what it can do. It can take a while before you fully understand just how awesome the modern browser has become; there is a reason we decided to target the browser like we do – because it’s practically an operative system in its own right.

Tasty but simple effects can play a major role when done right

Tasty but simple effects can play a major role when done right

But while Smart creates HTML elements by code, relieving you of the ultimate boring task of writing HTML structures and tinkering with inconsistencies between browsers — our CSS styles are still a 100% manual affair.

A new take on CSS

The problem with generating CSS from code has been twofold:

  • Injecting CSS rules into an existing stylesheet is very tricky
  • The ability to edit and ship an application with “a theme” trumps any notion of auto generated CSS

Well for the past two versions of Smart we have shipped the product with a stylesheet class. This class basically creates a fresh new style-sheet, and allows you to register rules, effects, backgrounds and whatever you need – at runtime.

I decided to give this class a make-over, basically re-writing it from scratch to take height for Internet Explorer. I also started to tinker with something very exciting, namely an easier way of generating CSS effects in your code.

Generating cool effects is now super easy

Generating cool effects is now super easy

And this is the important part. You don’t want to create ordinary styles by code, that belongs in the standard CSS stylesheet; What you want to control by code is effects programming and custom CSS tailored for controls “on demand” and executed immediately.

First, let us take a look at the CSS generation code:

class function  TSuperStyle.AnimGlow(aFrom,aTo:TColor):String;
var
  mStyles:  TDarthStyleSheet;
  mWriter:  TCSS;
begin
  mStyles:=getStyleSheet;
  if mStyles<>NIL then
  Begin
    result:=w3_GetUniqueObjId;

    mWriter:=TCSS.Create;
    try
      mWriter
        .KeyFrames.inc(result + " ")
        .Enter
          .from
          .enter.BoxShadow(0,0,0,0).leave.CRLF

          .PercentOf(50)
          .Enter.boxShadow(0,0,12,0,aTo).leave.CRLF

          .to
          .enter.BoxShadow(0,0,0,0).leave.CRLF
        .Leave .CRLF;

        mStyles.Add(mWriter.Text);
        mWriter.text:="";

        mWriter
          .inc("." + result + "_player ")
          .enter
            .AnimationName(result)
            .AnimationDuration(2,0)
            .AnimationInfinite
          .leave;
        mStyles.add(mWriter.text);
    finally
      mWriter.free;
    end;
    result:=result + "_player";
  end;
end;

Looks messy right? Well you should see what the code really looks like. You can imagine having to do string-replacement on names, colors and various parameters. The above code is infinitely more flexible than a fixed string. Well, let’s have a look at the CSS rules generated by our code:

@-webkit-keyframes OBJ16 {
  from {
    -webkit-box-shadow: 0px 0px 0px 0px;}
  50% {
    -webkit-box-shadow: 0px 0px 12px 0px #ff0000; }
  to {
    -webkit-box-shadow: 0px 0px 0px 0px;
  }
}

.OBJ16_player {
  -webkit-animation-name: OBJ16;
  -webkit-animation-duration: 2.0s;
  -webkit-animation-iteration-count: infinite;
}

What does this function do? It’s actually very sexy! The original routine registers both the animation – and then a style with the animation active. It also generates a name for the animation automatically (so no conflicts) – and the routine returns the name of the finished style.

With the name in hand, all you have to do to activate the style on an element is:

  w3button1.CSSClasses.Add(mName);

In the example above we animate a glowing, red 12px cloud around the button. It slowly fades into full red, then it fades back out into nothingness. It’s set to repeat forever, so for as long as the style is assigned to the control it remains visually active.

To remove the animation from our button, all we have to do is this:

  w3button1.CSSClasses.Remove(mName);

How cool is that! I’m really looking forward to more complex CSS animations. Perhaps have your forms curl across into view following a super-smooth beziercurve?

Needless to say I am secretly working on the Smart Mobile Studio presentation framework. It will give you complete control over CSS3, from GPU activation to the most complex animations and effects available.

So stay tuned..

Smart clouds, the big picture

April 11, 2015 Leave a comment

When people hear about cloud services, they tend to jusr think storage space and reduce the cloud phenomenon to a huge diskdrive in the sky. Perhaps it was unfortunate that storage was the first service to emerge from the cloud concept since so many people are reducing it’s potential to mere storage, but thankfully there are developers in the world who understand these things more in depth. And development is what I want to write about in this post.

The old way of doing things

If you work for a small or medium company chances are you have a web-server in your offices, perhaps in good company with an email server and a database server. This way of doing things has been the norm for many, many years now.

Cloud based software is setting the norm, are you ready for it?

Cloud based software is setting the norm, are you ready for it?

Whenever a new software product came out, we had to install the RPC stack (remote procedure call libraries) on the web-server and give it access to the database server. Then and only then could our native Dephi client connect via the internet to get the data.

The Delphi client application would make use of a RPC framework and call the procedures on the server just like they were local to the application.

Many companies are actually founded around delivering components and frameworks which makes this type of programming easier. The most notable company for Delphi programmers is no doubt Remobjects and the RemObjects SDK. This framework makes it very easy to write custom servers which communicates through industry standard message formats (JSON, XML, BINARY).

Another such framework which is open-source and free is the mORMot framework. Mormot is known for achieving great speed. The framework is built from the ground up and does not rely to much on third party code (Remobjects requires Indy for many of it’s server components).

Benefits of the RPC model

This way of writing programs, where the majority of operations reside on the server – while a client only connects and make the server functionality available locally for a customer, have plenty of benefits. Which is why it’s so popular and fun to build.

With the internet of things (IOT) you need a language which reaches all platforms

With the internet of things (IOT) you need a language which reaches all platforms

The first benefit is that you have full control over both the internal mechanics of the service and it’s data. You dont deliver code which is cracked and abused by pirates and hackers; Your code resides safely on your personal servers and only valid accounts can access it. Your total control over the database means means that working generating in-house statistics is a snap. You will not be affected by server traffic to the extent that your customers are.

But those are only minor perks, the really huge advantage is that you are able to consolidate all your clients towards a single RPC standard. In other words: you implement the application framework once on the server, and all your clients connect and make use of the same RPC service. Your iPhone, Android and win32 desktop clients all connect and use the same server. The same goes for your Linux and OS X desktop applications, and (drumroll) also your ISAPI web application.

The new model

There is nothing wrong with the old model. The way you would organize such a distributed application is logical and more or less the way it has to be. It allows you to de-couple your database from your service (the remote procedure call API you are exposing) and your service from the platform dependent clients.

How flexible is your service? Can it move around?

How flexible is your service? Can it move around?

It gives you plenty of options as well. Since the database is typically on a separate machine running mySQL, MariaDB or MSSQL, it makes it easier to hot-swap the location of the database should you decide to move it. Maybe you found a DB host in Germany at an affordable price, meaning that you can move your data there with no more work involved than changing IP and login credentials.

But all of this so far, is the way we used to do things (or are still doing things). With the cloud we are able to work with the infrastructure at a higher level. We no longer scale up simply coding a proxy and setting up another service or physical machine — no we clone the whole machine virtual image (vmware image for instance) which runs the service with the click of a button.

The same goes for the database needs. We dont just setup a proxy and X number of physical machines mirroring the same data (although we can do that as well), no – we clone the entire machine instance and chain the data into one huge, massive datacenter.

Building applications the smart way

Imagine you could do all of the above, but using a language which doesn’t require physical machines, a virtual server instance or a full vmware image. What if you could work exactly like before, using the same language even, but target a server platform which allows you to scale both horizontally and vertically? (read: both in number of services and their capacity).

Your services must grow in scale with your business

Your services must grow in scale with your business

But it doesn’t stop there; what if you could also run your services on any platform you want, be it Linux, OS X, Unix or Linux. What if you could just forget about platform and runtime all together and focus completely on what your services should do?

In other words

  • You author the service(s) in object pascal
  • You compile and target a universal platform
  • You can move your services between platforms
  • You have full access to databases
  • Your code is de-coupled from the database driver (portable)
  • Your service framework uses industry standard message formats
  • Your service framework uses ordinary REST protocols
  • Your service can be called and utilized from all your clients

What does this mean? It means that you author your service in Smart Pascal, which compiled to nodeJS compatible JavaScript. NodeJS can be hosted affordably on a minimal cloud instance (as opposed to a full virtual server instance which native Delphi services require). Your service can be cloned and scaled to handle increasing payload as your customer-base grows.

You will be able to move your entire service and online presence between providers without change in code. Tired of Amazon? Simply copy your files to Azure or another provider which supports nodeJS. Or why not make use of a normal website hosting service which is often fast, affordable and widespread?

This is the Smart Mobile Studio model. Giving you the power and tools to truly tap into and deliver killer cloud applications.

Combined with the fact that Smart Mobile Studio was designed for mobile applications you will be able to target iOS, Android, Microsoft Phone, Blackberry and HTML5 from the exact same codebase (!)

Leverage existing services

Smart Mobile Studio and our focus on platform independent nodeJS code is not out to eradicate existing technology, far from it. While we believe Smart Pascal is by far the best and outright smartest choice for modern distributed application programming – we recognize that a single product cant deliver everything.

We regard our product as one utility in a toolbox of many. As a developer it’s important to be versatile and flexible, adapting to customer need and technical excellence. And as such

As such we support frameworks like RemObjects SDK directly in our IDE. This means that your HTML5 and mobile applications can now talk directly to existing native Remobjects services. We also support Embarcadero Datasnap which gives your smart app’s the ability to connect, authenticate and consume your existing data services out of the box.

 

Get Smart Mobile Studio for 1 year

April 11, 2015 2 comments
Know Delphi or FPC? Then sign up now!

Know Delphi or FPC? Then sign up now!

The Smart Competition has been extended by 1 month, which means that you have ample time to join and code some interesting stuff with Smart Mobile Studio.

But ! I have decided to make the prices more interesting by adding a full 1 year subscription to Smart Mobile Studio pro (!) as the first price, and the Raspberry PI 2B as the second price and a Raspberry PI model 1 (the original RPI) as our third place price.

So we now have 3 prices which are as follows:

  1. Smart Mobile Studio Pro (1 yr subsc.)
  2. Raspberry PI model 2 B (Windows 10)
  3. Raspberry PI model 1 A (Linux only)

Wow! what is this competition about?

Simple. The winners will be picked from the entries and the 3 best components or packages will receive the prices.

Note: Please ship the components as a smart mobile studio package. Creating a SMS package is very easy, see the packages menu. This is not a must, but by far the easiest way for us to test the components and see them in action (demo program + package = good experience).

Writing slick HTML5 components is easy, fun and rewarding!

Smart needs stuff like this – are you up for the challenge?

What should I write components with?

Simply go to www.smartmobilestudio.com and download the trial. Remember to request a trial key (!) before you begin or you wont get access to the IDE.

With SMS installed, play around with it and get to know how it works. Especially SmartCL.Components is of interest for this competition – and then code a kick ass component or package which is noteworthy, unique and helpful.

Keep in mind that Smart Mobile Studio has few components, so controls which are old classics for Lazarus and Delphi – are completely new and valid here!

You can read the original competition post here!

Swirly graphics

April 9, 2015 Leave a comment

Just did a small 10 minute experiment in Smart Pascal. Essentially what I want is to be able to pre-calculate a nice soft path between X number of points. Which is essentially what is known as a bezier curve. This can be used in many situations from plotting pixels, moving sprites or indeed – animating elements with CSS.

Here is my 10 minute experiment:

function bezier(p1,p2,p3,p4:TPoint;t:float):TPoint;
begin
  var mum1 := 1- t;
  var mum13 := mum1 * mum1 * mum1;
  var mu3 := t * t * t;

  result:=TPoint.Create(
    round(mum13 * p1.x + 3*t * mum1*mum1 * p2.x+3*t*t * mum1*p3.x + mu3*p4.x),
    round(mum13 * p1.y + 3*t * mum1*mum1 * p2.y+3*t*t * mum1*p3.y + mu3*p4.y) );
end;

procedure TForm1.W3Button1Click(Sender: TObject);
var
  mBitmap:  TBitmap;
  x:  Integer;
  p1,p2,p3,p4:  TPoint;
begin
  mBitmap:=TBitmap.create;
  try
    mBitmap.Allocate(400,400);

    p1:=TPoint.Create(10,60);
    p2:=Tpoint.create(100,40);
    p3:=Tpoint.create(180,60);
    p4:=Tpoint.create(200,180);

    mBitmap.canvas.pen.color:=clRed;
    mBitmap.canvas.MoveTo(p1);
    mBitmap.canvas.lineTo(p2);
    mBitmap.canvas.lineto(p3);
    mBitmap.Canvas.lineto(p4);

    var f :=0.0;
    for x:=0 to 100 do
    begin
      f:=x / 100;
      var mpt := bezier(p1,p2,p3,p4,f);
      writeln(mpt.toString());
      mBitmap.canvas.Pixels[mpt.x,mpt.y]:=clBlue;
    end;

    w3panel1.Background.FromURL(mBitmap.Canvas.ToDataURL('png'));

  finally
    mBitmap.free;
  end;
end;

Lo and behold the mighty swirley path!

Oh its so nice and soft and swirley

Oh its so nice and soft and swirley

Patching the Smart Mobile Studio RTL

April 8, 2015 Leave a comment

With the Smart Mobile Studio update around the corner (with the tip of the nose visible around the corner actually) there is going to be a lot of new and cool things to play with. But before you get you hands on it, you can actually patch the old RTL quite easily.

In this example I am going to implement a true HTML5 disable/enable functionality. This may sound odd, what do I mean? Enable disable? Dont all controls have a Enabled property?

Well yes, but for a browser Enabled only makes sense for input boxes, combo-boxes and buttons. Setting Enabled:=False on a panel for instance, which is essentially a run-time created DIV element, has absolutely no meaningful purpose what so ever.

Figuring things out

But part of being a programmer is to figure things out, so I have made a really cool solution to this problem. For just stop and think for a moment — what should happen when you set Enabled to false? Let’s say you disable a panel with 100 child components on it – what exactly do you want to happen?

That final touch makes all the difference

That final touch makes all the difference

Truth is there is only one way to deal with this and that is to recursively tell all the child controls that they should not accept any mouse, keyboard or touch interaction. But that would be a horrible solution because – just think of all that stack activity! A control can have quite a few child controls – so the number of elements that have to suddenly take height for the new state can be overwhelming (read: slow as syrup).

So how did I solve this? Easy: cascading styles!

Cascades of awesomeness

Ever wondered why CSS is short for cascading style sheets? Like where exactly does the “cascade” part come into play? An element can actually have more than one style assigned to it. You can make 100 different styles and assign them all to the same elements actually — which would be a fantastic mess, but it would be perfectly legal.

The browser would simply try to merge the styles together, and the colors, images and whatever decoration you have assigned to it would be merged. This final “merged” product is what is known as the calculated style. This is the style which the browser renders to the screen.

Using more than one style

So how do we truly disable an element without performing a recursive callback suicide? We define a style which disables all mouse and touch interaction – and also alter the visible style of a control to appear different. Preferably ghost-like to ensure that the user regards the element as disabled.

Secondly, we patch the RTL to add this style to any control which get’s the Enabled property set to false, and subsequently remove the style again when Enabled is set to true.

So in SmartCL.Components we find the method SetEnabled() as a member of TW3CustomControl. We simply modify that like this:

procedure TW3CustomControl.SetEnabled(aValue: Boolean);
begin
  Handle.disabled := not aValue;
  if aValue then
  Begin
    if w3_hasClass(handle,'disabledState') then
    w3_removeClass(handle,'disabledState');
  end else
  w3_addClass(handle,'disabledState');
end;

And then we add the following CSS to our stylesheet (note: if you dont have a CSS file in your project you are using a default theme. Simply go into project options -> linker and check the “use custom theme” option. This will create a CSS file for you with all the styles from the default stylesheet).

Simply add this to the top of the CSS-file:

.disabledState {
  background-color: #FFFFFF;
  -webkit-pointer-events: none !important;
     -moz-pointer-events: none !important;
      -ms-pointer-events: none !important;
       -o-pointer-events: none !important;
          pointer-events: none !important;
  cursor: no-drop !important;
}

.disabledState *{
	opacity: 0.70 !important;
}

The first style (.disabledState) simply disables pointer interaction (pointer here meaning mouse, touch etc. responses), and also it changes the mouse cursor.

The second style is a bit special, the * character means “all” just like in SQL, so what we say here is that if an element has the disabledState class, all it’s children will attain the properties in that style. In this case we alter the opacity of child controls to 70%.

And with that — you have a fully working Enable / Disable patched RTL!

Smart Mobile Studio For Business

April 8, 2015 1 comment

This is a topic which surfaces from time to time. I completely understand that people whole are new to Smart Mobile Studio, people who havent had time to get into the whole HTML5 “shift” in technology that has occurred for the past 6 years have to ask. And I am very happy to answer such questions, it’s why we made the product to begin with – to help Delphi and Lazarus developers preserve their hard-earned knowledge and use their skillset on a new and exciting platform: namely HTML5 and the cloud.

So is Smart Mobile Studio up for the challenge of business apps? Let’s have a look.

The application

Wilma, screenshot from application

Wilma, screenshot from application

While we have several customers who use and work exclusively with Smart Mobile Studio as their primary development platform, the first and most obvious example for me has to be StarSoft. StarSoft OY is a company from Finland, one of Norway’s neighbours (The Smart Company is Norwegian). One of its developers is Jarto Tarpio which I have had the good fortune of talking with on several occasions. I must admit that Jarto is not an average programmer, his insight into both Delphi and Smart Mobile Studio and the speed at which he adopted the technology demonstrates that he has a solid grasp of both native and virtual environments. So as far as case studies goes, Jarto cannot be called a complete beginner.

StarSoft has produced their latest application, simply called Wilma, written from scratch in Smart Mobile Studio. It’s an application which targets the Finnish school system, and can be downloaded from Google Store and Apple Appstore. The application has around 100.000 downloads and is a good example of what can be achieved using Smart Mobile Studio alone.

You can view the application here (Google AppStore)

Wilma

In Jarto’s own words “When it comes to feedback, we’ve got a lot of good feedback, but there are also a lot of 1-ratings from kids who hate going to school” which is to be anticipated I guess for an app that empowers teachers and parents with access to the public school system, with real-time messaging if someone has skipped class among the features 🙂

Jarto was nice enough to write a few words in response to a Facebook debate, here is a verbatim copy of his reply about Smart Mobile Studio:

“let me tell my reasons for going with SMS instead of Delphi when it came to mobile apps: I didn’t like Delphi’s slow compiler in mobile development. I also fought a long time to get Delphi to recognize my Android device to be able to debug on it – and failed. I didn’t like the way everything needed to be set up for iOS development. SMS was a lot simpler and faster. I also noticed, that app speeds were about the same, so there was no clear advantage of using Delphi compared to SMS. I also did a test of filling a TListBox with a 1k lines on Delphi and noticed that it took a lot of time on Android, so I figured that I needed to write my own listboxes no matter which tool I used. And the last reason is my goal of using the same codebase for iOS, Android and Windows Phone. We already do use 100% same source code with SMS on iOS and Android, but haven’t started to use it on Windows Phone yet. The app itself has about 100k total downloads. There have been problems with really old Android phones, but otherwise it has worked well. When it comes to feedback, we’ve got a lot of good feedback, but there are also a lot of 1-ratings from kids who hate going to school” -Source: Jarto Tarpio, StarSoft OY

Snapshots

Below are some snapshots from Google Store. As you can see Jarto and the team at StarSoft have used Smart Mobile Studio exactly as it was supposed to be used. With a rich CSS style made for the app, custom controls written and adapted for the solution and focus on code which delivers on all platforms. The application is available for both Android and iOS from the same codebase with a Microsoft Phone version in the pipeline.

Wilma, screenshot from application

Wilma, screenshot from application

Wilma, screenshot from application

Wilma, screenshot from application

Wilma, screenshot from application

Wilma, screenshot from application

The Darth component package for Smart Mobile Studio

April 7, 2015 2 comments
Black and stylish UI

Black and stylish UI

I am pleased to announce that work has begun on the Darth component package. This is a special component set for Smart Mobile Studio version 1.2 and above (package support) which provides Windows 8.1 mobile controls and styles.

Darth?

Microsoft mobile (Windows 8.1) features a slick, black UI with plenty of animation and transition effects. The name “darth” was selected when a member of the team called this UI for “that Darth Vader theme from Microsoft”. The name stuck with the code and despite it’s obvious clash with the Dart programming language – we decided to keep it. We are empire men after all.

Darth implements a wide range of slick and awesome components from Windows 8.1 mobile. All components work on Microsoft mobile, Apple IPhone and Android phones as well. But we are tailoring this package especially for Windows Phone developers.

The components

As of writing the following components are scheduled for the Darth package

  • TDarthCategoryHeader
  • TDarthHorizontalRuler
  • TDarthVerticalRuler
  • TDarthOrigoBox
  • TDarthLayoutControl
  • TDarthHtmlViewer
  • TDarthTextViewer
  • TDarthSwitch
  • TDarthButton
  • TDarthToolbar
  • TDarthMessageDialog
  • TDarthContextMenu
  • TDarthFormSlider
  • TDarthHorizontalScrollbar
  • TDarthVerticalScrollbar
  • TDarthStarfield
  • TDarthScrollText

Darth also comes with loads of classes. Most interesting is the fact that Darth generates CSS effects “on the fly”, which means it can build and construct complex effects which are injected into it’s own stylesheet in memory. After use the style is unregistered and removed automatically.

Another interesting class is the particle engine and effects, which makes it easy to add impact impressions and speed indicators. It’s also suitable for games and multimedia alike.

Release date

Darth will be released in good Microsoft style — when it’s ready 🙂 Although we expect it to be launched towards the end of this summer.

Smart competition extended to may 1st!

April 6, 2015 Leave a comment
Smart Pascal Compo

Smart Pascal Compo

Time has run out for the Smart Mobile Studio component competition. but I guess I picked a bad time for this, with easter and school holidays getting in the way of things.

As I wrote regarding rules we need a minimal number of entries to call it a competition. At the moment we have only 3 entries – although I have received a fair bit of email regarding details, the rules etc. (which I thought I outlined with great precision *smile*).

And let’s face it — it’s a super easy competition. Yesterday I wrote a fully fledged component for Smart Mobile Studio. A complete implementation of the Windows 8.1 mobile category header. You can check that out here. The point being that writing components for Smart Mobile Studio is much easier than Delphi or Lazarus. It’s really fun!

As a bonus the official list of components that ship with Smart is spartan and young, so chances are you will be able to find a control which is not there quite easily.

One more time

I feel it would be premature to simply cancel at this point. So I will extend the deadline to span april – which means the final draw is now on the 1st of may!

If there is still not enough entries, then I guess I’ll cancel the competition all together. And naturally according to rules, no submitted code will be used (unless you want to) in teaching.

The Raspberry PI 2 model b price (!)

Surely a Raspberry PI 2 model B must be worth a couple of hours coding? Especially now with Windows 10 just around the corner ! I personally own 4 of these little gems. One is dedicated for retro gaming, another is used as a backup server, a third is used as a dedicated nodeJS server (which I use with Smart Mobile Studio) and the last one is an all-round coding testbed. Only the nodeJS and gaming RPI’s are version 2 model B, the two others are version 1 and 1 B respectively.

Windows 10 is just around the corner

Windows 10 is just around the corner

It’s a really great little computer. It runs on 5V so it’s extremely reasonable (you can leave it on 24/7 without being afraid of high electricity bills). And it’s particularly suited for single-server tasks. Perfect for nodeJS or Remobjects SDK servers (compiled with Lazarus and FPC for ARM CPU).

Writing nodeJS servers with Smart Mobile Studio is so much fun, and I promise you that it’s going to be a real game changer once you get into it. You use the Raspberry PI to model a full server architecture at home, and when it’s done — you just deploy it vertically onto the cloud. And then you can scale it horizontally (clone instances) as your business grows.

Motivation

The primary motivation for this competition is to support object pascal in our education system; Such as the Pascal programming for Schools Project in the UK. Object Pascal in all it’s forms is an excellent language for beginners and advanced alike. It has the depth of C/C++ but with a friendly and intuitive syntax suitable for all levels. It’s a perfect language and excellent for kids and teenagers to acquaint themselves with what programming is all about.

You might not know it but classical pascal was actually engineered for schools. The language itself was created to be easy to teach and easy to learn – and at the same time replace C/C++ with all it’s quirks and idiosyncrasies.

But students need help from us adults with examples, study material and quality code. Hence the emphasis that source-code be documented as much as possible. Be clear and easy to read – and so on.

If you havent seen the Pascal programming from schools project, then you should check it out! They have their own category dedicated to Smart Pascal with some really great stuff!

I’m still blown away by the arrow-shooting game written by an 11-year-old – which uses angle calculations and momentum to fire arrows at a target. Or this little particle engine which is fun and easy to learn 🙂

Getting into the competition

If you own Smart Mobile Studio, or just want to try it out — then join the competition! If you don’t have Smart Mobile Studio and want to join, then you can go to http://www.smartmobilestudio.com, download the trial and request a trial serial number.

The last bit is important because a lot of people download the trial and think it’s bugged — you need a valid serial number when you start SMS for the first time, or you wont be able to fire it up.

Then what? Easy – send me an email with your entry. Use the email lennart DOT aasenden AT gmail DOT com

 

 

Catch quick swipes in Smart Mobile Studio

April 5, 2015 2 comments
Windows 8.1 mobile category header

Windows 8.1 mobile category header

Smart Mobile Studio has full support for gesture events, but there are some scenarios where wrapping the whole shabam is just pure overkill. One such case is my latest component: A Windows Mobile 8 category header. It’s a full implementation of the Windows 8.1 mobile category header, complete with CSS3 transformation and GPU powered scrolling.

The Windows 8.1 mobile category header

If you own a Windows 8.1 mobile device you have probably seen this header in action many times. It’s basically just a black horizontal panel. Inside is X number of categories, where the current selected category is highlighted with a white color, while non-selected categories are in a dark grey color.

In the picture to the right you can see it at the top of the display below the “select players” caption. Under the header is a normal pick-list as it’s called in Visual Studio SDK. The category header is de-coupled from the list below it, which gives a nice effect since they move and scroll at different speeds.

Behavior

When you swipe to the right or left the category on either side, depending on what way you swiped, the content scrolls smoothly and centers the selected item.

It’s a very simple little thing but visually very effective, since it tells you where you are and also where you can navigate to next. It’s also very intuitive since you immediately realize that you can move through the different categories by swiping to the left or right.

But do we really need to handle the full gesture API just for this? I think not. It’s overkill for such a small task.

Secondly, since this is a component designed to be re-used and dropped into a project, we dont want to use the gesture events. Component developers traditionally leave the published events alone so that their customers can enjoy the full spectrum of events in their development cycle.

Well, to catch quick swipes in the general directions (left, right, up, down) I decided to implement this in a base-class. And here it is.

NOTE: Please note that you need the recent beta to compile this on your version of Smart Mobile Studio.

unit SmartCL.GestureDetect;

interface

uses
  System.types,
  system.colors,
  system.dateutils,
  SmartCL.System,
  SmartCL.graphics,
  SmartCL.Components;

type

  TW3QuickSwipeInfo = Record
    begins: TDateTime;
    sX: Integer;
    sY: Integer;
    eX: Integer;
    eY: Integer;
  end;

  TW3SwipeDirection = (sdNone=0,sdLeft,sdRight,sdDown,sdUp);

  TSwipeDetectedEvent = Procedure (sender:TObject;Direction:TW3SwipeDirection);

  TW3QuickSwipeBase = class(TW3CustomControl)
  private
    FSwipeDet:  TW3QuickSwipeInfo;
    FMinX:      Integer = 20; //  [20]--X--[&gt;&gt;]
    FMaxX:      Integer = 40; //  [&lt;&lt;]--X--[40]
    FMinY:      Integer = 40;
    FMaxY:      Integer = 50;
    FDirection: TW3SwipeDirection;
    FOnSwipe:   TSwipeDetectedEvent;
    FTouchHandleStart:  THandle;
    FTouchHandleMove:   THandle;
    FTouchHandleUp:     THandle;
  public
    procedure   setupGestures;
    procedure   removeGestureDetection;
    function    gestureDetection:Boolean;
  published
    Property  OnSwipe:TSwipeDetectedEvent read FOnSwipe write FOnSwipe;
  end;

implementation

function TW3QuickSwipeBase.gestureDetection:Boolean;
begin
  result:=(FTouchHandleStart) and (FTouchHandleMove) and (FTouchHandleUp);
end;

Procedure TW3QuickSwipeBase.setupGestures;
begin
  FTouchHandleStart:=handle.addEventListener('touchstart', procedure (e:variant)
    begin
      e.preventDefault;
      var t := e.touches[0];
      FSwipeDet.sx:=t.screenX;
      FSwipeDet.sy:=t.screenY;
    end);

  FTouchHandleMove:=handle.addEventListener('touchmove', procedure (e:variant)
    begin
      e.preventDefault;
      if (e.touches) then
      Begin
        if e.touches.length&gt;0 then
        begin
          var t := e.touches[0];
          FSwipeDet.eX:=t.screenX;
          FSwipeDet.eY:=t.screenY;
          FSwipeDet.begins:=now;
        end;
      end;
    end);

  FTouchHandleUp:=handle.addEventListener('touchend', procedure (e:variant)
    var
      mTicks: Integer;
    begin
      e.preventDefault;

      FDirection:=sdNone;

      (* How many Ms since touch and release? *)
      mTicks:=MillisecondsBetween(FSwipeDet.begins,now);
      if mTicks &lt; 10 then
      begin

        if (FSwipedet.ex - FMinx &gt; FSwipeDet.sx)
        or (FSwipeDet.ex + FMinx &lt; FSwipeDet.sx) then
        begin
          if (FSwipeDet.ey &lt; (FSwipedet.sy + FMaxY))
          and (FSwipeDet.sy &gt; (FSwipeDet.ey - FMaxY)) then
          begin
            if (FSwipeDet.ex &gt;  FSwipeDet.sx) then
            FDirection:=sdRight else
            FDirection:=sdLeft;
          end;
        end;

        if ((FSwipeDet.ey - FMinY) &gt; FSwipeDet.sy)
        or ((FSwipeDet.ey + FMiny) &lt; FSwipeDet.sY) then
        begin
          if  (FSwipeDet.ex &lt; (FSwipeDet.sx + FMaxX))
          and (FSwipeDet.sx &gt; (FSwipeDet.ex - FMaxX)) then
          begin
            if FSwipeDet.ey &gt; FSwipeDet.sY then
            FDirection :=sdDown else
            FDirection :=sdUp;
          end;
        end;

        if FDirection&lt;&gt;sdNone then
        w3_requestAnimationFrame( procedure ()
          begin
            if assigned(OnSwipe) then
            OnSwipe(self,FDirection);
          end);
      end;
    end);
end;

procedure TW3QuickSwipeBase.removeGestureDetection;
begin
  if Handle.valid
  and handle.ready
  and not (csDestroying in ComponentState) then
  begin
    if (FTouchHandleStart) then
    Handle.removeEventListener(FTouchHandleStart);
    if (FTouchHandleMove)  then
    Handle.removeEventListener(FTouchHandleMove);
    if (FTouchHandleUp)    then
    Handle.removeEventListener(FTouchHandleUp);
  end;
end;

end.

Right, when you derive your controls from this baseclass, all you have to do is to call setupGestures() in the constructor (initializeObject) and finally removeGestureDetection() in the destructor. Then just catch the OnSwipe event in your ancestor.

The black category menu in action

Work in progress

Voila, you will now be able to detect quick swipes to the right,left,upwards and downwards.
Below is how I used it to write the Smart Mobile version of the Windows 8 category header.

The final product

No article like this would be complete without a sneak peak at the final product. I realize the irony of not being able to display it live here, but sadly WordPress doesnt allow embedding JS/HTML5 which is a real shame. But here is a picture of the final version. I also adapted the CSS to pick the right fonts for MS-phones, iOS, Android and desktop.

Snappy animations and easy navigation

Snappy animations and easy navigation


uses
  System.Types,
  system.typecon,
  System.colors,
  SmartCL.GestureDetect,
  SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms,
  SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Label, SmartCL.Controls.ListMenu, SmartCL.Controls.Memo;

type
  TWin8CategoryItem = Class;

  IItemHost = Interface
    procedure ItemAltered(Item:TWin8CategoryItem);
  end;

  TCategoryChange = (ccAdded,ccDeleted,ccClear,ccItemChange);

  ICategoryHost = Interface
    procedure CategoriesAltered(Item:TWin8CategoryItem;const Change:TCategoryChange);
  end;

  TWin8textItem = Class(TW3CustomControl)
  protected
    procedure StyleTagObject;override;
  public
    Property  CategoryItem: TWin8CategoryItem;
  end;

  ISubItem = Interface
    procedure setCtrl(value:TWin8textItem);
    function  getCtrl:TWin8textItem;
  end;

  TWin8SlideMenu  = partial class(TW3QuickSwipeBase);

  TWin8CategoryItem = Class(TW3OwnedObject,ISubItem)
  private
    FOnClick:   TNotifyEvent;
    FWidth:     Integer;
    FHeight:    Integer;
    FCaption:   String;
    FControl:   TWin8textItem;
    Procedure   setCaption(value:String);
  protected
    procedure   setCtrl(value:TWin8textItem);
    function    getCtrl:TWin8textItem;
  public
    Procedure   ReCalc;
  Public
    property    Caption:String read FCaption write setCaption;
    Property    Width:Integer read FWidth;
    Property    Height:Integer read FHeight;
    Property    OnClick:TNotifyEvent read FOnClick write FOnClick;
  end;

  TWin8Categories = Class(TW3OwnedObject,IItemHost)
  private
    FItems:   Array of TWin8CategoryItem;
    procedure ItemAltered(Item:TWin8CategoryItem);
  public
    Property  Owner:TWin8SlideMenu
              read ( TWin8SlideMenu( inherited Owner ) );
    property  Count:Integer read ( FItems.Count );
    property  Items[index:Integer]:TWin8CategoryItem
              read ( FItems[index] );

    function  Add:TWin8CategoryItem;
    function  IndexOf(const Item:TWin8CategoryItem):Integer;
    procedure Delete(index:Integer);
    Procedure Clear;
  end;

  TWin8Slider = Class(TW3CustomControl);

  TWin8ItemSelectedEvent = Procedure (sender:TObject;Category:TWin8CategoryItem);

  TWin8SlideMenu = Class(TW3QuickSwipeBase,ICategoryHost)
  private
    FObjects:   TWin8Categories;
    FSlider:    TWin8Slider;
    FSelected:  TWin8CategoryItem;
    FUnSelectedColor: TColor;
    FSelectedColor:   TColor;
    FOnSelected:  TWin8ItemSelectedEvent;
    procedure   setSelectedColor(const Value:TColor);
    procedure   setUnSelectedColor(const value:TColor);
  protected
    procedure   setSelected(value:TWin8CategoryItem);
    procedure   CategoriesAltered(Item:TWin8CategoryItem;
                const Change:TCategoryChange);
    procedure   LayoutItems;
    Procedure   CenterSelected;
  protected
    procedure   InitializeObject;Override;
    procedure   FinalizeObject;Override;
    Procedure   ObjectReady;Override;
    procedure   Resize;Override;
    Procedure   StyleTagObject;override;
  public
    Property    SelectedItem: TWin8CategoryItem
                read FSelected write setSelected;
    property    Categories:TWin8Categories read FObjects;

    Procedure   First;
    procedure   Last;
    Procedure   Next;
    procedure   Previous;

  published
    Property    OnCategorySelected:TWin8ItemSelectedEvent
                read FOnSelected write FOnSelected;

    property    SelectedColor:TColor read FSelectedColor write setSelectedColor;
    property    UnSelectedColor:TColor read FUnSelectedColor write setUnSelectedColor;
  end;

//############################################################################
// TWin8textItem
//############################################################################

procedure TWin8textItem.StyleTagObject;
begin
  inherited;
  self.font.size:=22;
end;

//############################################################################
// TWin8SlideMenu
//############################################################################

procedure TWin8SlideMenu.InitializeObject;
begin
  inherited;
  FObjects:=TWin8Categories.Create(self);
  Font.Size:=22;
  FSlider:=TWin8Slider.Create(self);
  self.FUnSelectedColor:=clGrey;
  self.FSelectedColor:=clWhite;
  FSlider.Background.FromColor(clBlack);

  self.OnSwipe:=Procedure (Sender:TObject;Direction:TW3SwipeDirection)
    begin
      case Direction of
      sdNone: background.fromColor(clNone);
      sdLeft: Next;
      sdRight:Previous;
      sdUp:   background.fromColor(clCyan);
      sdDown: background.fromColor(clblue);
      end;
    end;

  self.OnKeyDown:=procedure (sender:TObject;aKeyCode: Integer)
  begin
    case aKeyCode of
    37: Previous;   //  right
    38: First;      //  up
    39: Next;       //  left
    40: Last;       //  down
    end;
  end;

  Handle.ReadyExecute( procedure ()
    begin
      w3_setAttrib(handle,'tabindex',0);
    end);

  self.setupGestures;
end;

procedure TWin8SlideMenu.FinalizeObject;
begin
  FObjects.free;
  FSlider.free;
  inherited;
end;

Procedure TWin8SlideMenu.First;
begin
  if not (csDestroying in ComponentState) then
  begin
    if (csReady in ComponentState) then
    begin
      if Categories.count&gt;0 then
      SelectedItem:=Categories.Items[0] else
      if SelectedItem&lt;&gt;NIL then
      SelectedItem:=NIL;
    end;
  end;
end;

procedure TWin8SlideMenu.Last;
Begin
  if not (csDestroying in ComponentState) then
  begin
    if (csReady in ComponentState) then
    begin
      if Categories.count&gt;0 then
      begin
        if SelectedItem&lt;&gt;Categories.Items[Categories.count-1] then
        SelectedItem:=Categories.Items[Categories.count-1];
      end;
    end;
  end;
end;

Procedure TWin8SlideMenu.Next;
var
  mIndex: Integer;
begin
  if not (csDestroying in ComponentState) then
  begin
    if (csReady in ComponentState) then
    begin
      if SelectedItem&lt;&gt;NIL then
      begin
        mIndex:=Categories.IndexOf(SelectedItem);
        if mIndex&lt;Categories.Count-1 then
        SelectedItem:=Categories.items[mIndex+1] else
        selectedItem:=Categories.items[0];
      end else
      Begin
        if categories.Count&gt;0 then
        SelectedItem:=Categories.Items[0];
      end;
    end;
  end;
end;

procedure TWin8SlideMenu.Previous;
var
  mIndex: Integer;
begin
  if not (csDestroying in ComponentState) then
  begin
    if (csReady in ComponentState) then
    begin

      if SelectedItem&lt;&gt;NIL then
      begin
        mIndex:=Categories.indexOf(SelectedItem);
        if mIndex&gt;0 then
        SelectedItem:=Categories.items[mIndex-1] else
        selectedItem:=Categories.Items[Categories.count-1];
      end else
      begin
        if categories.count&gt;0 then
        selectedItem:=Categories.Items[Categories.count-1];
      end;
    end;
  end;
end;

procedure TWin8SlideMenu.setSelectedColor(const Value:TColor);
begin
  if Value&lt;&gt;FSelectedColor then
  begin
    if (csReady in ComponentState) then
    Begin
      Beginupdate;
      FSelectedColor:=Value;
      addToComponentState([csMoved]);
      EndUpdate;
    end else
    FSelectedColor:=Value;
  end;
end;

procedure TWin8SlideMenu.setUnSelectedColor(const value:TColor);
begin
  if Value&lt;&gt;FUnSelectedColor then
  begin
    if (csReady in ComponentState) then
    begin
      beginUpdate;
      FUnSelectedColor:=Value;
      AddToComponentState([csMoved]);
      endUpdate;
    end else
    FUnSelectedColor:=Value;
  end;
end;

Procedure TWin8SlideMenu.styleTagObject;
begin
  inherited;
end;

Procedure TWin8SlideMenu.ObjectReady;
begin
  inherited;
  W3_RequestAnimationFrame(procedure ()
    begin
      LayoutItems;
      if  (SelectedItem=NIL)
      and (Categories.Count&gt;0) then
      SelectedItem:=Categories.items[0];
    end);
end;

Procedure TWin8SlideMenu.CenterSelected;
var
  dx: Integer;
  mCtrl:  TW3CustomControl;
begin
  if  (FSelected=NIL)
  and (Categories.Count&gt;0) then
  FSelected:=Categories.items[0];

  if FSelected&lt;&gt;NIL then
  Begin
    mCtrl:=(FSelected as ISubItem).getCtrl;
    if mCtrl&lt;&gt;NIL then
    begin
      dx:=-(mCtrl.left + (mCtrl.width div 2));
      inc(dx, (clientwidth div 2) );
      FSlider.fxMoveTo(dx,2,0.3, procedure ()
        var
          mCtrl:  TWin8textItem;
        begin
          mCtrl:=(FSelected as ISubItem).getctrl;
          mCtrl.Font.Color:=FSelectedColor;

          if assigned(FOnSelected) then
          FOnSelected(Self,FSelected);

        end);
    end;
  end;
end;

procedure TWin8SlideMenu.setSelected(value:TWin8CategoryItem);
var
  mCtrl:  TW3CustomControl;
begin
  if Value&lt;&gt;FSelected then
  begin

    (* Change color or currently selected item *)
    if FSelected&lt;&gt;NIl then
    begin
      try
        mCtrl:=(FSelected as ISubItem).getctrl;
        if mCtrl&lt;&gt;NIL then
        mCtrl.Font.Color:=FUnSelectedColor;
      except
        on e: exception do;
      end;
    end;

    (* set new selection *)
    FSelected:=Value;

    (* Center selected element *)
    If  (csReady in ComponentState)
    and (FSelected&lt;&gt;NIL) then
    CenterSelected;
  end;
end;

procedure TWin8SlideMenu.LayoutItems;
var
  x:  integer;
  mTotalWidth: Integer;
  dx: Integer;
  mCtrl:  TW3CustomControl;
begin
  for x:=0 to self.Categories.Count-1 do
  Begin
    categories.items[x].ReCalc;
    inc(mTotalWidth,categories.items[x].Width + 4);
  end;

  if mTotalWidth&lt;&gt;FSlider.width then
  FSlider.width:=mTotalWidth;

  dx:=0;
  for x:=0 to self.Categories.Count-1 do
  begin
    mCtrl:=(Categories.Items[x] as ISubItem).getctrl;
    if mCtrl&lt;&gt;NIL then
    begin
      mCtrl.SetBounds(dx,0,Categories.items[x].width,Categories.items[x].height);
      mCtrl.InnerHTML:=Categories.items[x].Caption;
      inc(dx,Categories.items[x].width);
      inc(dx,4);
    end;
  end;
end;

procedure TWin8SlideMenu.CategoriesAltered(Item:TWin8CategoryItem;
          const Change:TCategoryChange);
var
  mDisp:  TWin8textItem;
  mAccess:  ISubItem;
begin
  case Change of
  ccAdded:
    Begin
      (* Create text conatiner element *)
      mDisp:=TWin8textItem.Create(FSlider);

      (* Connect container to our item object *)
      mAccess:=(Item as ISubItem);
      mAccess.setCtrl(mDisp);

      (* Initialize the element *)
      mDisp.BeginUpdate;
      try
        mDisp.width:=22;
        mDisp.height:=22;
        mDisp.CategoryItem:=Item;
        mDisp.font.name:=self.Font.Name;
        mDisp.Font.Size:=self.Font.size;
        mDisp.font.color:=FUnSelectedColor;
        mDisp.Background.FromColor(clNone);
      finally
        mDisp.EndUpdate;
      end;

      (* Hook resize of text element *)
      mDisp.OnResize:=Procedure (sender:TObject)
        var
          mParent:  TWin8Slider;
          mItem:    TWin8textItem;
        Begin
          mItem:=TWin8textItem(sender);
          mParent:= TWin8Slider( mItem.Parent );
          if mParent&lt;&gt;NIL then
          begin
            if mParent.height&lt;&gt;mItem.height then
            mItem.height:=mParent.Height;
          end;
        end;

      mDisp.OnClick:=procedure (sender:TObject)
        var
          mObj:   TWin8textItem;
        begin
          mObj:=TWin8textItem(sender);
          SelectedItem:=mObj.CategoryItem;
        end;

      w3_requestAnimationFrame(LayoutItems);
    end;
  ccDeleted:
    Begin
      mDisp:=(item as ISubItem).getCtrl;
      mDisp.free;
    end;
  ccClear:
    begin
    end;
  ccItemChange:
    begin
      selectedItem:=NIL;
      if (csReady in ComponentState)
      and not (csDestroying in ComponentState) then
      LayoutItems;
    end;
  end;

end;

procedure TWin8SlideMenu.ReSize;
var
  x:        Integer;
  mItem:    TWin8CategoryItem;
  mheight:  Integer;
begin
  inherited;
  if (csReady in ComponentState) then
  begin
    for x:=0 to Categories.Count-1 do
    Begin
      mItem:=Categories.items[x];
      if mItem.Height&gt;mHeight then
      mHeight:=mItem.height;
    end;
    if mHeight=0 then
    mHeight:=clientHeight-2;

    self.FSlider.top:=2;
    self.FSlider.height:=mHeight;
    //self.FSlider.Height:=clientHeight-4;
  end;
end;

//############################################################################
// TWin8Categories
//############################################################################

Procedure TWin8Categories.Clear;
var
  mItem:TWin8CategoryItem;
begin
  try
    for mItem in FItems do
    mItem.free;
  finally
    FItems.clear;
  end;
end;

procedure TWin8Categories.ItemAltered(Item:TWin8CategoryItem);
begin
  if assigned(Owner) then
  begin
    (Owner as ICategoryHost).CategoriesAltered
    (Item,TCategoryChange.ccItemChange);
  end;
end;

function  TWin8Categories.Add:TWin8CategoryItem;
begin
  result:=TWin8CategoryItem.Create(self);
  FItems.add(result);
  (Owner as ICategoryHost).CategoriesAltered(result,ccAdded);
end;

function  TWin8Categories.IndexOf(const Item:TWin8CategoryItem):Integer;
begin
  result:=FItems.indexOf(Item);
end;

procedure TWin8Categories.Delete(index:Integer);
begin
  FItems.delete(index);
end;

//############################################################################
// TWin8CategoryItem
//############################################################################

procedure TWin8CategoryItem.setCtrl(value:TWin8textItem);
begin
  FControl:=Value;
end;

function TWin8CategoryItem.getCtrl:TWin8textItem;
begin
  Result:=FControl;
end;

Procedure TWin8CategoryItem.setCaption(value:String);
var
  mHost:  TWin8SlideMenu;
begin
  FCaption:=Value;
  ReCalc;
  if (owner&lt;&gt;NIL) then
  begin
    mHost:=TWin8Categories(Owner).Owner;
    if (csReady in mHost.ComponentState) then
    begin
      (mHost as ICategoryHost).CategoriesAltered
      (self,TCategoryChange.ccItemChange);
    end;
  end;
end;

Procedure TWin8CategoryItem.ReCalc;
var
  mHost:  TWin8SlideMenu;
  mSize:  TW3TextMetric;
begin
  if Owner&lt;&gt;NIl then
  begin
    mHost:=TWin8Categories(Owner).Owner;
    mSize:=mHost.MeasureText(StrReplace(FCaption,&quot; &quot;,&quot;_&quot;));
    FWidth:=mSize.tmWidth;
    FHeight:=mSize.tmHeight;
  end;
end;

Message API goes beta, Smart Mobile Studio

April 4, 2015 Leave a comment
Clockwork API

Clockwork API

A lightweight version of the QTX message framework has been included in the upcoming hotfix beta for Smart Mobile Studio.

The message API has been previously described here and here. The API itself consolidates older, Win32 type programming with the fully Object Oriented architecture of Smart Mobile Studio

Importance of messages

JavaScript is single threaded event based. This means that dispersing tasks and steps in a process is important. Messages, similar to WinAPI messages, is ideal for the JavaScript environment and processing model.

Messages are especially practical for database bindings and informing visual controls regarding changes in a data-set.

Working with messages

Messages under Smart Mobile Studio are classes, rather than structures (records) like under Delphi or FreePascal. When creating special purpose messages you inherit from TCustomMessage (or TWindowsMessage if you want to target message subscribers by handle).

Receiving messages are done through a message subscription class. You create an instance of such a class, then register the class-types you wish to subscribe to. When such a message enters the message-stack, it is dispatched to all subscribers.

  var
  FHandler: TMessageSubscriber;

  FHandler.OnMessage:=Procedure (const Sender:TMessageSubscriber;const Message:TCustomMessage)
  Begin
    writeln("MESSAGE RECIEVED!");
    message.done;
  end;

  var msg:TMyMessage:=TMyMessage.Create;
  msg.Text:="This is cool stuff!";

  postmessage(msg);

Win32 Emulation

When porting code from Delphi or Lazarus to HTML5, it can be tricky to emulate or refactor code which relies on messages. As such we have included an emulation layer especially for this.

Messages which inherit from TWindowsMessage are treated differently. Each message-subscriber exposed a THandle which simulates a HWND handle in Windows. When using TWindowsMessage you can use sendMessage() to target a message-subscriber via it’s handle.

We also added a shorthand constructor exactly for this type of conversion:

  var
  FHandler: TMessageSubscriber;

  type
  TWMPaint = Class(TWindowsMessage);

  //Using the shorthand constructor to
  //simplify winAPI emulation
  SendMesage(TWmPaint.Create(WM_PAINT,0,0));

Message stack

Below is the final draft for the message-stack. It is roughly 40% of the original IPC found in the QTX library.

unit system.messages;

interface

uses
  System.types,
  system.typecon,
  system.memory,
  system.streams,
  SmartCL.System;

  (*  Message API
      ===========
      Both Delphi and Lazarus/FPC provides message stack wrappers around
      the Windows API. FPC also emulates the windows message stack when
      running under Linux and OS X (or indeed any OS which is not Windows).

      Messages are very helpful and leverages many programming tasks
      which would otherwise be extremely hard to accomplish.

      Smart Mobile Studio deals with messages quite differently from both
      Delphi and Lazarus in that our messages are object instances rather
      than records. This provides a much richer means of passing information
      between instances, because the information does not need to fit
      into a 8 byte storage space.

      I have included a special message-type which will help aid the
      conversion of WinAPI software to HTML5: namely TWindowsMessage.
      This class contains the fields ordinary TMessage records contain
      under Delphi and Lazarus.

      Another difference is that Postmessage() is not handle-based. A handle
      under WinAPI requires a window-handle, which naturally HTML5 doesnt
      provide. As such, Message Subscribers create a custom handle on
      creation - which can be targeted exactly like a HWND handle under
      WinAPI. To use this functionality messages must be dispatched with
      SendMessage().

      In short:
        - PostMessage() does not support targeting handles
        - SendMessage() requires target handle
        - Handles are created for each message subscriber
        - Messages are dispatched to all subscribers who have the class-type
          registered (i.e they subscribe to that message class)
        - When a message's "done" method is called, it stops the message
          from being further dispatched (read: message consumed).

      MISC
      ====

      The priority interval for processing messages is set by the constant
      CNT_MSG_DELAY by default. You can override this in an application by
      calling SetMessageHandlingPriority() to set another millisecond delay
      between message dispatching. The default value is 33ms.
  *)

  const
  CNT_MSG_DELAY = 33;

  type

  TCustomMessage      = class;
  TMessageSubscriber  = Class;
  TMessageClass       = Class of TCustomMessage;


  (* TCustomMessage is the base message-type. You inherit your own
     message types from this class.
     To catch a message you must subscribe to it by creating a message
     subscription class, and then register the class there, as such:

      FSubScription:=TMessageSubscriber.Create;
      FSubScription.SubScribeTo([MessageClass1,MessageClass2]);
      FSubScription.Onmessage := procedure (Sender:TMessageSubscriber
                    Message:TCustomMessage);
        begin
          try
            // React to message
          finally
            /* By calling done the message will not be
               dispatched to more subscribers */
            message.done;
          end;
        end;
  *)

  TCustomMessage  = Class(TObject)
  private
    FDone:      Boolean;
  public
    Property    MessageDone:Boolean read FDone;
    procedure   Done;
  end;

  (* Windows Emulation message:
     This message-type is defined to provide an easier emulation
     path when porting WinAPI applications from Delphi or Lazarus.
     The Constructor allows you to compose "quick" messages

      For example:
      postmessage(handle, TWindowsMessage.Create($1200,L,W) );

     *)
  TWindowsMessage = Class(TCustomMessage)
  private
    FLParam:  Integer;
    FWParam:  Integer;
    FId:      Integer;
  public
    Property    Id:Integer;
    Property    LParam:Integer;
    Property    WParam:Integer;
    Constructor Create(Id,LParam,WParam:Integer);virtual;
  end;

  IMessageSubscriber = Interface
    function  QuerySubscription(const clsid:TMessageClass):Boolean;
    procedure Dispatchmessage(const msg:TCustomMessage);
  end;

  TMessageHandlerEvent = procedure (const Sender:TMessageSubscriber;
                         const Message:TCustomMessage);

  TMessageSubscriber = Class(TObject,IMessageSubscriber)
  private
    FHandle:      THandle;
    FItems:       Array of TMessageClass;
    FEnabled:     Boolean;
    FOnMessage:   TMessageHandlerEvent;
  protected
    function      QuerySubscription(const clsid:TMessageClass):Boolean;virtual;
    procedure     DispatchMessage(const msg:TCustomMessage);virtual;
  published
    Property      Handle:THandle read FHandle;
    Property      OnMessage:TMessageHandlerEvent
                  read FOnMessage write FOnMessage;

    (* Subscribe to messages *)
    procedure     SubscribeTo(const clsid:TMessageClass);overload;
    procedure     SubScribeTo(const MsgClasses:Array of TMessageClass);overload;

    (* Un-subscribe from message classes *)
    procedure     UnSubscribeFrom(const clsid:TMessageClass);overload;
    procedure     UnSubscribeFrom(const MsgClasses:Array of TMessageClass);overload;

    (* To enable/disable message dispatching on this subscriber *)
    Procedure     Disable;
    Procedure     Enable;

    Constructor   Create;virtual;
    Destructor    Destroy;Override;
  end;


  procedure PostMessage(const Msg:TCustomMessage);

  procedure SendMessage(const Handle:THandle;
            const Msg:TWindowsMessage);

  Procedure SetMessageHandlingPriority(const Value:Integer);

implementation

var
_subscribers: Array of TMessageSubscriber;
_tableid: Integer = 210973;
_updateFreq:Integer = CNT_MSG_DELAY;

_MsgStack:  Array of TCustomMessage;

function getNewID:THandle;
begin
  inc(_tableid);
  result:=TVariant.CreateObject;
  result["id"] := _tableid;
end;

Procedure SetMessageHandlingPriority(const Value:Integer);
begin
  _updateFreq:=Value;
end;

procedure PostMessage(const msg:TCustomMessage);
begin
  if msg<>NIL then
  begin
    if _MsgStack.IndexOf(msg)<0 then
    _MsgStack.Push(msg);
  end;
end;

procedure SendMessage(const Handle:THandle;
          const Msg:TWindowsMessage);
var
  mSub: TMessageSubscriber;
begin
  for mSub in _subscribers do
  begin
    if mSub.Handle["id"] = Handle["id"] then
    begin
      (mSub as IMessageSubscriber).DispatchMessage(msg);
      msg.free;
      break;
    end;
  end;
end;

Procedure RegisterSubscriber(Const Instance:TMessageSubscriber);
Begin
  if _SubScribers.IndexOf(Instance)<0 then
  _subscribers.add(Instance);
end;

procedure UnRegisterSubscriber(const Instance:TMessageSubscriber);
var
  mIndex: Integer;
Begin
  mIndex:=_SubScribers.IndexOf(Instance);
  if mIndex>=0 then
  _subscribers.Delete(mIndex);
end;

//############################################################################
// TWindowsMessage
//############################################################################

Constructor TWindowsMessage.Create(Id,LParam,WParam:Integer);
begin
  inherited Create;
  self.id:=Id;
  self.LParam:=LParam;
  self.WParam:=WParam;
end;

//############################################################################
// TCustomMessage
//############################################################################

procedure TCustomMessage.Done;
begin
  FDone:=true;
end;

//############################################################################
// TMessageSubscriber
//############################################################################

Constructor TMessageSubscriber.Create;
begin
  inherited Create;
  FEnabled:=True;

  RegisterSubscriber(self);
  FHandle:=getNewID;
end;

Destructor TMessageSubscriber.Destroy;
begin
  UnRegisterSubscriber(self);
  inherited;
end;

Procedure TMessageSubscriber.Disable;
begin
  FEnabled:=False;
end;

Procedure TMessageSubscriber.Enable;
begin
  FEnabled:=True;
end;

procedure TMessageSubscriber.SubScribeTo(const MsgClasses:Array of TMessageClass);
var
  mClass: TMessageClass;
begin
  for mClass in MsgClasses do
  SubScribeTo(mClass);
end;

procedure TMessageSubscriber.SubScribeTo(const clsid:TMessageClass);
begin
  if clsID<>NIL then
  begin
    if FItems.IndexOf(clsid)<0 then
    FItems.add(clsid);
  end;
end;

procedure TMessageSubscriber.UnSubscribeFrom
          (const MsgClasses:Array of TMessageClass);
var
  mClass: TMessageClass;
begin
  for mClass in MsgClasses do
  UnSubscribeFrom(mClass);
end;

procedure TMessageSubscriber.UnSubscribeFrom(const clsid:TMessageClass);
begin
  if clsid<>NIL then
  begin
    var mId:=Fitems.IndexOf(clsid);
    if mId>=0 then
    FItems.delete(mid,1);
  end;
end;

function TMessageSubscriber.QuerySubscription
          (const clsid:TMessageClass):Boolean;
var
  x:  integer;
begin
  if FEnabled then
  begin
    for x:=0 to FItems.Count-1 do
    begin
      result:=(FItems[x] = clsid);
      if result then
      break;
    end;
  end;
end;

procedure TMessageSubscriber.DispatchMessage
          (const msg:TCustomMessage);
begin
  if msg<>NIL then
  begin
    if not msg.MessageDone then
    begin
      if QuerySubscription(TMessageClass(msg.ClassType)) then
      Begin

        if assigned(FOnMessage) then
        begin
          try
            FOnMessage(self,msg);
          except
            on e: exception do;
          end;
        end;
        msg.Done;
      end;
    end;
  end;
end;

procedure ProcessMessages;
var
  Msg: TCustomMessage;
  x:  Integer;
begin
  if _MsgStack.Count>0 then
  begin
    Msg:=_MsgStack.Pop;
    for x:=0 to _subscribers.count-1 do
    begin
      if (_subScribers[x] as IMessageSubscriber)
         .QuerySubscription(TMessageClass(msg.classType)) then
      Begin
        (_subScribers[x] as IMessageSubscriber).DispatchMessage(msg);
        if msg.MessageDone then
        Begin
          msg.free;
          break;
        end;
      end;
    end;
  end;
  w3_setTimeOut(ProcessMessages,_updateFreq);
end;


Initialization
begin
  ProcessMessages;
end;


end.

Windows 8.1 mobile, a brand new look

April 2, 2015 1 comment

I cant really remember last time I was so utterly stoked by a piece of technology; Not even when I got my first iPhone did I experience true joy of owning something that actually was helpful, powerful and entertaining at the same time. The iPhone was more of a fashion statement; not that I care too much about that – but that’s what it felt like after a day or two. As a developer it didn’t take me long to figure out that what I could do with my mobile device was in fact nothing. In fact the only way to get my software on the phone was to throw even more cash into the Apple money machine, download XCode and force myself to learn objective C. No one should be forced to learn such a disgusting language. No one.

Well today I found a real bargain and did a great coop. Microsoft is selling their top-level phone, the Lumia 930, for a whopping 4199 NKR, which is roughly 410 € (or thereabouts) without a cell subscription. All the local stores where I live offer the same phone for around 1500 if you sign up for a 1 year mobile subscription, which would set me back roughly 550 NKR a month for a whole year. You get the phone cheap, but you end up paying an arm and a leg for it.

A display to make even the iPhone 6 seem slim

A display to make even the iPhone 6 seem slim

But as luck would have it one store chain had an easter sale, and among the items was the Lumia 930 — at a flabbergasted 2199 NKR. That’s half the price of what Microsoft Store is asking for it. Needless to say I went for it straight away. I don’t think I have ever paid so much for a phone to be honest, like most Norwegians I tend to only buy phones in combination with a subscription – so I get a cheap fancy new phone every year. Last time it was the iPhone 6, before that the Samsung Galaxy S4 (worst phone ever!) and before that iPhone 5S, 4S and 3GS -and way back before touch screens I owned a HTC Windows phone.

Is it any good?

You know, I recently bought a low-end Lumia 530 for my home office. As you know I spend my spare time working on Smart Mobile Studio, so obviously I need mobile devices to test our code. So getting a cheap 750NKR phone made sense. I never expected it to be THAT good. In fact I stopped using my iPhone almost completely in exchange for a phone costing 1/7th of the iPhone 6 (!)

It really is a fantastic piece of technology! Those that know me personally or who follow my blog know that I rarely get stoked over phones. My passion is in coding and creating software, not fiddle around with devices (well, give or take a Raspberry PI project). Hopefully you will take my word for it and try one of these phones, especially the 930 model, because it’s truly worth every penny.

Think about it this way: make a list of what you think should be different about the iPhone. Then create a list of what should be different for Android. Both these platforms have flaws and technical decisions which doesn’t work in real life. But I think when you compare those lists with the Microsoft based phone you will find, just like I did, that Microsoft has really managed to balance out the stuff you hate about iOS and Android.

Microsoft OS 8.1 really works well

Microsoft OS 8.1 really works well

On Android everything goes. There are no rules and no responsibilities. The google app store is evident of this because 50% of the entire app stock is of such low quality that it borders on junk. If you have owned an iPhone – switching to Android is not recommended because the flip in quality will shock you. The phone looks cool and the UI animations etc. plays a trick on you, but once you really get into the nitty-gritty it’s a bloody mess.

The iPhone on the other hand is a solid product, no doubt about that. It’s polished, streamlined and Apple have spent a lot of time and money making sure that its smooth sailing all the way. But while the consumer experience is of high quality and assurance, the system suffers a complete lack of personalization and ownership. I write “ownership” because you are really not expected to use an Apple product outside the guidelines defined by Apple. To me this is a retarded attitude because what I do with my own phone is ultimately my choice, it’s my bloody phone and no one can tell me what to do with my own things.

Well that’s not how Apple regards the situation. And as a result there are aspects of the iPhone which the consumer is completely locked out of. You can’t even mount the internal-drive, but you are limited to a mock USB connection where only selected parts of the filesystem is visible. So much for using disk recovery software to rescue images and files you have accidentally deleted.

The middle way

Where Android has a policy of anything goes and Apple is the diametrically opposite (nothing goes, our way or no way!) – Microsoft represents a golden mean of the two, a middle way if you like. You are allowed to copy your own software to your phone as much as you like. The only restriction is that when you want to sell and publish your software, you have to go through proper channels. That is sort of to be expected. They also do quality assurance just like Apple does, which I think is a very good thing to do, because it stops hobby programmers flooding app store with rip-offs and homebrewed scams. It’s not uncommon on google store to find some kid in india publishing 30-40 variations of the same app, filled to the hilt with commercials and banners — rendering whatever the function of the app(s) to useless. So filtering out stuff like this is important.

The filesystem is also open, just like Android, but Microsoft has hidden some critical OS files. Which is fine. You don’t want to accidentally delete a library file and kill your phone. But all in all, you are allowed to browse around your own phone, copy over music and video and (most importantly) your own software.

This thing of being able to write and use your own software on your own device, which is your property from A to Z once you have bought it, is very important to be. It’s important because a mobile device such as a modern phone is “not just a phone” anymore. It’s a mobile mini computer. And since we are software developers this means that our rights should carry more weight than whatever a produces feels about it. They sell a product, we paid for it — it’s ours. End of story.

In no other industry can people be told what to do with their own property. Think about that for a minute. Would Volvo, Volkswagen, Porsche or whatever brand of car you prefer be able to tell you how to drive? Or how to style your car? Or what to have in your glove compartment? Hell no you would tell them to stuff themselves and laugh at any car producer trying to tell you what to do with your own property.

Same with computers. Would you allow someone to dictate that you cannot install an operating system on your PC? Nope. If you want to install Linux, Windows, Amiga OS or OS X for that matter — you would laugh and shake your head if someone suddenly tried to force you to only use their software, their way and having to pay for doing so continuously.

Yet people are willing to accept almost anything regarding their phones, including being told how to NOT use them. It’s absurd and completely mind-boggling how stupid people are, allowing Apple to dictate what to do with their own property. Heck, I bootstrapped mine and hacked it hours after I purchased it. Then I downloaded 1 terrabyte of apps free from a torrent site. So bite me Apple, you’re not getting another penny out of me.

Music

Music has been Apple’s stronghold for a while now. Well, I am happy to inform you that the Lumia 930 model has a built-in music service. As does the low-end 530 model as well. In essence it works like this: you pick 3 artists you enjoy and store that as a “mix”. Microsoft will then use those 3 artists to calculate what type of music you like (remember: you can create as many mixes as you want) and build a continuous stream of music matching your mix style.

And it doesn’t cost you a single dime! It’s free, open, 100% — play as much as you want 24/7 !

I listened for 2 days straight when I got the Lumia 530 phone, and it doesn’t cost a penny. You can also download and make the mixes resident, which means you can play them in your car without internet access. And once again — it’s a free service for Microsoft phone users.

So what exactly do I need iTunes for? Considering that I can buy the music I like from Amazon or directly from the XBox music network. Not only do I get the music in formats I can re-use on all my devices (MP3 or MP4), but Microsoft doesn’t try to hide my files in obscure storage schemes like Apple does.

But best of all, you get to enjoy all the latest music for free through the mix station. For free. I cant underline that enough.

I guess there is a reason Apple try to undermine the Lumia every chance they get – because it is a superior phone, no doubt at all. And this comes from a person who own 6 mac’s and two Apple blade servers. Not to mention iPads, Apple TV products and phones. So I have no reason to lie about any of this.

Think twice

The next time you are on the prowl for a new phone, do yourself a favour and check out the high-end Microsoft phones. Some like Android and some like Apple — but don’t you find it limiting with just two types of phones? How can you say that you have chosen a phone when you havent really checked out all of them?

The Microsoft phones are exceptionally good to use, and I sincerely hope you try the Lumia series because they are worth every penny. You will never own a better phone I can promise you that. It’s the best of iPhone and Android all rolled up in one – but without the defects!

Oh and Cortana, the voice activated assistent on the Lumia makes Apple’s SIRI look like a brain-damaged monkey. I was able to dictate, correct and send an SMS from scratch using nothing but my voice! And remember that I am Norwegian so my “americaneese” is not exactly brooklyn kosher.

But lo and behold — cortana really works and it works so much better than Siri.

Sorry Apple, but Microsoft really kicked your ass and made a better phone – in all aspects.