Bangle.js Software Modification

As it comes, Bangle.js provides several utility functions that other apps use to provide more functionality.

For example:

  • E.showMessage shows a message
  • E.showAlert shows a message with an 'ok' button
  • E.showPrompt shows a message with multiple buttons
  • E.showMenu shows a menu where items can be selected and tweaked
  • Bangle.setUI provides easy access to Bangle.js buttons/touchscreen

For usage info on these, see the reference

These functions are built in and work a certain way, but they can be changed if you don't like the look of them, for instance with the Small Menus App.

You might want to change the positioning, font size, or even the way you interact with the menus completely!

So how does this work?

  • Get the original implementation
  • Test it out locally
  • Make modifications
  • Write them to your Bangle.js
  • Turn your modifications into an app

For this example, we'll look at E.showMessage as it's nice and simple.

Get the original implementation

In most cases, the implementation of the function will be in JavaScript in the Espruino Repository, but it's worth checking.

For E.showMessage you're taken to the Pixl.js implementation (there can be more than one implementation) which looks like this:

/*JSON{
    "type" : "staticmethod",
    "class" : "E",
    "name" : "showMessage",
    "generate_js" : "libs/js/pixljs/E_showMessage.min.js",
    "params" : [
      ["message","JsVar","A message to display. Can include newlines"],
      ["title","JsVar","(optional) a title for the message"]
    ],
    "ifdef" : "PIXLJS"
}
...
*/

So here you can see it's loading up libs/js/pixljs/E_showMessage.min.js. We can guess where the Bangle.js one is... libs/js/banglejs/E_showMessage.js

Note: sometimes there will be multiple versions of a file, like _Q3 (Bangle.js 2) and _F18 (Bangle.js 1)

Bear in mind these functions are generally written for execution speed and not readability!

Test it out locally

Now you have your file, copy it into the IDE with E.showMessage = before it (or whatever function you're trying to replace) and copy out one of the usage examples from the documentation to right below it - like this:

E.showMessage = function(msg,options) {
  if ("string" == typeof options)
    options = { title : options };
  options = options||{};
  g.clear(1); // clear screen
  Bangle.drawWidgets(); // redraw widgets
  g.reset().setFont("6x8",(g.getWidth()>128)?2:1).setFontAlign(0,-1);
  var Y = global.WIDGETS ? 24 : 0;
  var W = g.getWidth(), H = g.getHeight()-Y, FH=g.getFontHeight();
  var titleLines = g.wrapString(options.title, W-2);
  var msgLines = g.wrapString(msg||"", W-2);
  var y = Y + (H + (titleLines.length - msgLines.length)*FH )/2;
  if (options.img) {
    var im = g.imageMetrics(options.img);
    g.drawImage(options.img,(W-im.width)/2,y - im.height/2);
    y += 4+im.height/2;
  }
  g.drawString(msgLines.join("\n"),W/2,y);  
  if (options.title)
    g.setColor(g.theme.fgH).setBgColor(g.theme.bgH).
      clearRect(0,Y,W-1,Y+4+titleLines.length*FH).
      drawString(titleLines.join("\n"),W/2,Y+2);
  Bangle.setLCDPower(1); // ensure screen is on
};

E.showMessage("Lots of text will wrap automatically",{
  title:"Warning",
  img:atob("FBQBAfgAf+Af/4P//D+fx/n+f5/v+f//n//5//+f//n////3//5/n+P//D//wf/4B/4AH4A=")
})

You can now run it - make sure you upload to RAM:

You may also want to test it with widgets, in which case you can add these lines right before your test call:

Bangle.loadWidgets();
Bangle.drawWidgets();

Make modifications

Ok, now you can tweak the function - let's say we want to put a rounded border around the edge:

E.showMessage = function(msg,options) {
  if ("string" == typeof options)
    options = { title : options };
  options = options||{};
  g.clear(1); // clear screen
  Bangle.drawWidgets(); // redraw widgets
  g.reset().setFont("6x8",(g.getWidth()>128)?2:1).setFontAlign(0,-1);
  var Y = global.WIDGETS ? 24 : 0;
  var W = g.getWidth(), H = g.getHeight()-Y, FH=g.getFontHeight();
  var titleLines = g.wrapString(options.title, W-2);
  var msgLines = g.wrapString(msg||"", W-2);
  var y = Y + (H + (titleLines.length - msgLines.length)*FH )/2;
  var yt = Y + titleLines.length*FH;
  // colour everything
  g.setColor(g.theme.bgH).fillRect(0,Y,W-1,g.getHeight());
  // add a white inner with rounded borders
  g.setColor(g.theme.bg).
    fillRect(8,yt+16,W-8,g.getHeight()-16).
    fillRect(16,yt+8,W-17,g.getHeight()-8).
    fillCircle(16,yt+16,8).
    fillCircle(W-16,yt+16,8).
    fillCircle(16,g.getHeight()-16,8).
    fillCircle(W-16,g.getHeight()-16,8).
    setColor(g.theme.fg);
  // draw image
  if (options.img) {
    var im = g.imageMetrics(options.img);
    g.drawImage(options.img,(W-im.width)/2,y - im.height/2);
    y += 4+im.height/2;
  }
  // message body
  g.drawString(msgLines.join("\n"),W/2,y);  
  // title
  if (options.title)
    g.setColor(g.theme.fgH).setBgColor(g.theme.bgH).
      drawString(titleLines.join("\n"),W/2,Y+2);
  Bangle.setLCDPower(1); // ensure screen is on
};


E.showMessage("Lots of text will wrap automatically",{
  title:"Warning",
  img:atob("FBQBAfgAf+Af/4P//D+fx/n+f5/v+f//n//5//+f//n////3//5/n+P//D//wf/4B/4AH4A=")
})

Write them to your Bangle.js

This is really easy - simply delete all your test code, so you're left with just something like:

E.showMessage = function(msg,options) {
  // ...
};

Now:

  • Click the down-arrow next to the Upload icon in the IDE
  • Click Storage, New File
  • Enter mytweaks.boot.js as the name
  • Now click the Upload button

Nothing will happen immediately, but now try typing E.showMessage("Boo!") in the left hand side of the IDE - you'll get the new message box.

Your watch will now be usable as it was before, but all apps will have your updated menu.

Note: The next time you upload, the saved version of your code will not update because Bangle.js caches the boot files. You will need to type load("bootupdate.js") into the left-hand side of the IDE.

Turn your modifications into an app

Now everything is working, you can turn this into an app.

  • Follow the instructions for making an app if you haven't already
  • Think of a unique app ID (ideally all lowercase, no spaces or special characters) - I used mytweaks
  • Create a new folder like BangleApps/apps/mytweaks
  • In that folder, save your E.showMessage implementation as boot.js
  • Add a nice 48x48px icon as app.png
  • Now add the following metadata.json, remembering to change mytweaks to whatever app ID you decided to use:
{
  "id": "mytweaks",
  "name": "Rounded showMessage",
  "version": "0.01",
  "description": "Replace built in E.showMessage",
  "icon": "app.png",
  "type": "boot",
  "tags": "system",
  "supports": ["BANGLEJS2"],
  "storage": [
    {"name":"mytweaks.boot.js","url":"boot.js"}
  ]
}

And now you're done! You can either use it on your own personal app loader, or can submit it to the main Bangle.js app loader!

This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.