diff --git a/ide/static/ide/css/ib.css b/ide/static/ide/css/ib.css index 715807e7..d6b7798b 100644 --- a/ide/static/ide/css/ib.css +++ b/ide/static/ide/css/ib.css @@ -15,6 +15,78 @@ -webkit-filter: invert(100%); /* For Chrome/Safari/Opera - we actually prefer vendor-specific here. */ } +/* Colour picker from Slate */ +.item-color { + display: none; +} + +.item-styled-color { + position: relative; +} + +.item-styled-color .value { + border-radius: 5px; + border-color: #A8A8A8; + border-width: 1px; + border-style: solid; + display: block; + height: 40px; +} + +.item-styled-color .color-box-wrap { + display: none; + box-sizing: border-box; + position: absolute; + padding: 0 0 100% 0; + margin: 0.6em 0 0em; +} + +.item-styled-color .color-box-wrap.show { + display: block; +} + +.item-styled-color .color-box-wrap .color-box-container { + position: absolute; + background: repeating-linear-gradient(45deg, #aaa, #aaa 4px, #fff 5px, #fff 10px); + height: 99.97%; + width: 300px; + height: 300px; + left: 0; + top: 0; + z-index: 10; +} + +.item-styled-color .color-box-wrap .color-box-container .color-box { + float: left; + cursor: pointer; +} + +.item-styled-color .color-box-wrap .color-box-container .color-box.rounded-tl { + border-top-left-radius: 5px; +} + +.item-styled-color .color-box-wrap .color-box-container .color-box.rounded-tr { + border-top-right-radius: 5px; +} + +.item-styled-color .color-box-wrap .color-box-container .color-box.rounded-bl { + border-bottom-left-radius: 5px; +} + +.item-styled-color .color-box-wrap .color-box-container .color-box.rounded-br { + border-bottom-right-radius: 5px; +} + +/* Colour Pickers */ + +.ib-colours select { + width: 170px; +} + +.ib-colour-label { + margin-top: 29px; +} + /* Resizer */ .ib-resizer { @@ -88,33 +160,54 @@ /* ActionBarLayer */ -.ib-actionbarlayer { +.ib-canvas-sdk2 .ib-actionbarlayer { border-top-left-radius: 3px; border-bottom-left-radius: 3px; } .ib-actionbarlayer-icon { position: absolute; - left: 1px; - width: 18px; - height: 18px; text-align: center; background-repeat: no-repeat; pointer-events: none; } -.ib-icon-up { +.ib-canvas-sdk2 .ib-actionbarlayer-icon { + left: 1px; + width: 18px; + height: 18px; +} + +.ib-canvas-sdk3 .ib-actionbarlayer-icon { + left: 5px; + width: 22px; + height: 22px; +} + +.ib-canvas-sdk2 .ib-icon-up { top: calc(16% - 9px); } -.ib-icon-select { +.ib-canvas-sdk2 .ib-icon-select { top: calc(50% - 9px); } -.ib-icon-down { +.ib-canvas-sdk2 .ib-icon-down { top: calc(83% - 9px); } +.ib-canvas-sdk3 .ib-icon-up { + top: calc(19% - 11px); +} + +.ib-canvas-sdk3 .ib-icon-select { + top: calc(50% - 11px); +} + +.ib-canvas-sdk3 .ib-icon-down { + top: calc(80% - 11px); +} + /* MenuLayer */ .ib-menulayer { @@ -179,4 +272,10 @@ .ib-layerlistview li.selected { color: #333333; background-color: #969696; -} \ No newline at end of file +} + +/* Global canvas settings form */ + +.ib-settings select, .ib-settings input { + width: 140px; +} diff --git a/ide/static/ide/css/ide.css b/ide/static/ide/css/ide.css index c5017e42..c7f89f1e 100644 --- a/ide/static/ide/css/ide.css +++ b/ide/static/ide/css/ide.css @@ -770,7 +770,7 @@ table.build-results tr.pending .build-state { float: left; } -#ui-layer-list { +#ui-settings { padding-top: 20px; } diff --git a/ide/static/ide/js/colour_picker.js b/ide/static/ide/js/colour_picker.js new file mode 100644 index 00000000..d02ebe53 --- /dev/null +++ b/ide/static/ide/js/colour_picker.js @@ -0,0 +1,142 @@ +/* Modified Slate colour picker, from https://github.com/pebble/slate/blob/master/lib/js/main.js */ + +(function ($) { + 'use strict'; + + var ENUMS = { + COLOR: { + EMPTY: 'transparent' + } + }; + + $.extend($.fn, { + pebbleColourPicker: function (options) { + + var options = $.extend({}, { + sunny: false, + value_mapping: null + }, options || {}); + + var layout = [ + [false, false, '#55FF00', '#AAFF55', false, '#FFFF55', '#FFFFAA', false, false], + [false, '#AAFFAA', '#55FF55', '#00FF00', '#AAFF00', '#FFFF00', '#FFAA55', '#FFAAAA', false], + ['#55FFAA', '#00FF55', '#00AA00', '#55AA00', '#AAAA55', '#AAAA00', '#FFAA00', '#FF5500', '#FF5555'], + ['#AAFFFF', '#00FFAA', '#00AA55', '#55AA55', '#005500', '#555500', '#AA5500', '#FF0000', '#FF0055'], + [false, '#55AAAA', '#00AAAA', '#005555', '#FFFFFF', '#000000', '#AA5555', '#AA0000', false], + ['#55FFFF', '#00FFFF', '#00AAFF', '#0055AA', '#AAAAAA', '#555555', '#550000', '#AA0055', '#FF55AA'], + ['#55AAFF', '#0055FF', '#0000FF', '#0000AA', '#000055', '#550055', '#AA00AA', '#FF00AA', '#FFAAFF'], + [false, '#5555AA', '#5555FF', '#5500FF', '#5500AA', '#AA00FF', '#FF00FF', '#FF55FF', false], + [false, false, false, '#AAAAFF', '#AA55FF', '#AA55AA', false, false, false], + ]; + + var mappingSunny = { + '000000': '000000', '000055': '001e41', '0000aa': '004387', + '0000ff': '0068ca', '005500': '2b4a2c', '005555': '27514f', + '0055aa': '16638d', '0055ff': '007dce', '00aa00': '5e9860', + '00aa55': '5c9b72', '00aaaa': '57a5a2', '00aaff': '4cb4db', + '00ff00': '8ee391', '00ff55': '8ee69e', '00ffaa': '8aebc0', + '00ffff': '84f5f1', '550000': '4a161b', '550055': '482748', + '5500aa': '40488a', '5500ff': '2f6bcc', '555500': '564e36', + '555555': '545454', '5555aa': '4f6790', '5555ff': '4180d0', + '55aa00': '759a64', '55aa55': '759d76', '55aaaa': '71a6a4', + '55aaff': '69b5dd', '55ff00': '9ee594', '55ff55': '9de7a0', + '55ffaa': '9becc2', '55ffff': '95f6f2', 'aa0000': '99353f', + 'aa0055': '983e5a', 'aa00aa': '955694', 'aa00ff': '8f74d2', + 'aa5500': '9d5b4d', 'aa5555': '9d6064', 'aa55aa': '9a7099', + 'aa55ff': '9587d5', 'aaaa00': 'afa072', 'aaaa55': 'aea382', + 'aaaaaa': 'ababab', 'ffffff': 'ffffff', 'aaaaff': 'a7bae2', + 'aaff00': 'c9e89d', 'aaff55': 'c9eaa7', 'aaffaa': 'c7f0c8', + 'aaffff': 'c3f9f7', 'ff0000': 'e35462', 'ff0055': 'e25874', + 'ff00aa': 'e16aa3', 'ff00ff': 'de83dc', 'ff5500': 'e66e6b', + 'ff5555': 'e6727c', 'ff55aa': 'e37fa7', 'ff55ff': 'e194df', + 'ffaa00': 'f1aa86', 'ffaa55': 'f1ad93', 'ffaaaa': 'efb5b8', + 'ffaaff': 'ecc3eb', 'ffff00': 'ffeeab', 'ffff55': 'fff1b5', + 'ffffaa': 'fff6d3' + }; + + this.each(function () { + + var $color = $(this); + var $item = $color.parent(); + var grid = ''; + var itemWidth = 100 / layout[0].length; + var itemHeight = 100 / layout.length; + var boxHeight = itemWidth * layout.length; + + for (var i = 0; i < layout.length; i++) { + for (var j = 0; j < layout[i].length; j++) { + + var color = layout[i][j] || ENUMS.COLOR.EMPTY; + var selectable = 'selectable'; + + var roundedTL = (i === 0 && j === 0) + || i === 0 && !layout[i][j - 1] + || !layout[i][j - 1] && !layout[i - 1][j] + ? ' rounded-tl' : ''; + + var roundedTR = i === 0 && !layout[i][j + 1] + || !layout[i][j + 1] && !layout[i - 1][j] + ? ' rounded-tr ' : ''; + + var roundedBL = (i === layout.length - 1 && j === 0) + || i === layout.length - 1 && !layout[i][j - 1] + || !layout[i][j - 1] && !layout[i + 1][j] + ? ' rounded-bl' : ''; + + var roundedBR = i === layout.length - 1 && !layout[i][j + 1] + || !layout[i][j + 1] && !layout[i + 1][j] + ? ' rounded-br' : ''; + + if (options.sunny && color !== ENUMS.COLOR.EMPTY) { + color = '#' + mappingSunny[color.replace('#', '').toLowerCase()]; + } + + grid += '' + + ''; + } + } + + var $injectedColor = $('
' + + '' + + '
' + + '
' + + grid + + '
' + + '
' + + '
'); + $item.append($injectedColor); + + var $valueDisplay = $injectedColor.find('.value'); + + $injectedColor.on('click', function (ev) { + $item.find('.color-box-wrap').toggleClass('show'); + }); + + $item.find('.color-box.selectable').on('click', function (ev) { + ev.preventDefault(); + var value = $(this).data('value'); + var input_value = value; + if (_.isFunction(options.value_mapping)) { + input_value = options.value_mapping(value.replace('0x', '#')); + } + $color.val(input_value); + $valueDisplay.css('background-color', value.replace(/^0x/, '#')); + $color.trigger('change'); + $item.find('.color-box-wrap').removeClass('show'); + ev.stopPropagation(); + }) + }); + + return this; + } + }); +}(jQuery)); diff --git a/ide/static/ide/js/editor.js b/ide/static/ide/js/editor.js index ac4498a5..e87d0c8d 100644 --- a/ide/static/ide/js/editor.js +++ b/ide/static/ide/js/editor.js @@ -582,7 +582,7 @@ CloudPebble.Editor = (function() { }; var ib_pane = $('#ui-editor-pane-template').clone().removeClass('hide').appendTo(pane).hide(); - var ib_editor = new IB(ib_pane.find('.ui-canvas'), ib_pane.find('#ui-properties'), ib_pane.find('#ui-toolkit'), ib_pane.find('#ui-layer-list > div')); + var ib_editor = new IB(ib_pane.find('.ui-canvas'), ib_pane.find('#ui-properties'), ib_pane.find('#ui-toolkit'), ib_pane.find('#ui-layer-list > div'), ib_pane.find('#ui-settings')); var ib_showing = false; CloudPebble.GlobalShortcuts.SetShortcutHandlers({ @@ -728,12 +728,14 @@ CloudPebble.Editor = (function() { button_holder.append(error_area); button_holder.append(run_btn); button_holder.append(save_btn); - button_holder.append(discard_btn); - button_holder.append(rename_btn); if(source.indexOf('// BEGIN AUTO-GENERATED UI CODE; DO NOT MODIFY') != -1) { button_holder.append(ib_btn); } + + button_holder.append(rename_btn); + button_holder.append(discard_btn); + // You must have an app.js in pebblejs projects. if(CloudPebble.ProjectInfo.type != 'pebblejs' || file.name != 'app.js') { button_holder.append(delete_btn); diff --git a/ide/static/ide/js/ib/canvas.js b/ide/static/ide/js/ib/canvas.js index 45727996..1087b1a8 100644 --- a/ide/static/ide/js/ib/canvas.js +++ b/ide/static/ide/js/ib/canvas.js @@ -28,7 +28,7 @@ // Window properties var mProperties = { - bg: new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourWhite), + bg: new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourWhite, true), fullscreen: new IB.Properties.Bool(gettext("Fullscreen"), CloudPebble.ProjectInfo.app_is_watchface || CloudPebble.ProjectInfo.sdk_version == '3') }; mProperties.bg.on('change', handleBackgroundChange, this); @@ -44,13 +44,20 @@ function init(parent) { mNode = $('
'); mNode.on('mousedown', handleMouseDown); + mNode.toggleClass('ib-canvas-sdk2', CloudPebble.ProjectInfo.sdk_version == "2"); + mNode.toggleClass('ib-canvas-sdk3', CloudPebble.ProjectInfo.sdk_version == "3"); mNode.appendTo(parent); + render(); + + handleFullscreenChange(mProperties.fullscreen.getValue()); + } + + function render() { mScaleX = parent.width() / 144; mScaleY = parent.height() / 168; var cssTransform = 'scale(' + mScaleX + ',' + mScaleY + ')'; - mNode.css({ width: 144, height: 168, @@ -66,8 +73,6 @@ overflow: 'hidden', 'background-color': mProperties.bg.getValue().css }); - - handleFullscreenChange(mProperties.fullscreen.getValue()); } /** @@ -235,7 +240,7 @@ function handleBackgroundChange(colour) { mNode.css({ - 'background-color': colour.css + 'background-color': colour[IB.colourMode].css }); self.trigger('changeBackground', colour); } @@ -271,7 +276,7 @@ self.trigger('removelayer', layer); self.trigger('changed'); layer = null; - } + }; function handleChangeID(oldID, newID) { if(mChildren[oldID]) { @@ -340,14 +345,24 @@ mNode.empty(); }; + + /** + * Re-render the canvas and all its children + */ + this.refresh = function() { + render(); + _.invoke(mChildOrder, 'render', mNode); + }; + this.generateDeclaration = function() { return ["static Window *s_window;"]; }; this.generateInitialiser = function() { var initialiser = ["s_window = window_create();"]; - if(mProperties.bg.getValue() != IB.ColourWhite) { - initialiser.push("window_set_background_color(s_window, " + mProperties.bg.getValue() + ");"); + + if(!mProperties.bg.fullyEquals(IB.ColourWhite)) { + initialiser.push("window_set_background_color(s_window, " + mProperties.bg.generateCode() + ");"); } initialiser.push("#ifndef PBL_SDK_3"); initialiser.push(" window_set_fullscreen(s_window, " + mProperties.fullscreen.getValue() + ");"); @@ -363,7 +378,7 @@ _.each(properties, function(values, property) { switch(property) { case "window_set_background_color": - mProperties.bg.setValue(IB.ColourMap[values[0][1]]); + mProperties.bg.setValue(values[0][1]); break; case "window_set_fullscreen": mProperties.fullscreen.setValue(JSON.parse(values[0][1])); @@ -382,7 +397,7 @@ this.getBackgroundColour = function() { return mProperties.bg.getValue(); - } + }; this.getResources = function() { return mResources; diff --git a/ide/static/ide/js/ib/codeparser.js b/ide/static/ide/js/ib/codeparser.js index 84cac16e..5cbfab64 100644 --- a/ide/static/ide/js/ib/codeparser.js +++ b/ide/static/ide/js/ib/codeparser.js @@ -31,14 +31,34 @@ * @private */ _getPropertiesForLayerID: function(id) { + // Matches functions where 'id' is the first argument, and extracts the function name and its other arguments var regex = new RegExp('^\\s*([a-zA-Z_]+)\\s*\\(' + id + ',\\s*(.+)\\);$', 'gm'); + // Splits the remaining arguments by any commas, which aren't followed by closing brackets + var splitRegex = /,(?![^,]*\))/g; var groups; var props = Object.create(null); + // Look through the document for any functions whose first arguments are the desired layer ID. while((groups = regex.exec(this._source))) { if(!props[groups[1]]) { props[groups[1]] = []; } - props[groups[1]].push(_.invoke([groups[2]].concat(groups[2].split(',')), 'trim')); + var fullString = groups[2].trim(); + // Extract all function arguments. If any arguments are functions containing more arguments, + // extract the arguments of those functions. + var innerArgumentsRegex = /([A-Za-z_]+)\s*\((.*?)\)/g; + var args = _.chain(groups[2].split(splitRegex)) + .invoke('trim') + .map(function(argument) { + var innerGroup; + if ((innerGroup = innerArgumentsRegex.exec(argument)) != null) { + return _([innerGroup[1]].concat(innerGroup[2].split(splitRegex))).invoke('trim'); + } + else { + return argument; + } + }).value(); + var prop = [fullString].concat(args); + props[groups[1]].push(prop); } return props; }, diff --git a/ide/static/ide/js/ib/colours.js b/ide/static/ide/js/ib/colours.js new file mode 100644 index 00000000..950143b1 --- /dev/null +++ b/ide/static/ide/js/ib/colours.js @@ -0,0 +1,324 @@ +(function () { + IB.FullColourDescriptionMap = [ + { + "gcolour": "GColorMintGreen", + "html": "#AAFFAA", + "name": "Mint Green" + }, + { + "gcolour": "GColorElectricUltramarine", + "html": "#5500FF", + "name": "Electric Ultramarine" + }, + { + "gcolour": "GColorFolly", + "html": "#FF0055", + "name": "Folly" + }, + { + "gcolour": "GColorElectricBlue", + "html": "#55FFFF", + "name": "Electric Blue" + }, + { + "gcolour": "GColorArmyGreen", + "html": "#555500", + "name": "Army Green" + }, + { + "gcolour": "GColorChromeYellow", + "html": "#FFAA00", + "name": "Chrome Yellow" + }, + { + "gcolour": "GColorTiffanyBlue", + "html": "#00AAAA", + "name": "Tiffany Blue" + }, + { + "gcolour": "GColorPictonBlue", + "html": "#55AAFF", + "name": "Picton Blue" + }, + { + "gcolour": "GColorIndigo", + "html": "#5500AA", + "name": "Indigo (Web)" + }, + { + "gcolour": "GColorSpringBud", + "html": "#AAFF00", + "name": "Spring Bud" + }, + { + "gcolour": "GColorBrightGreen", + "html": "#55FF00", + "name": "Bright Green" + }, + { + "gcolour": "GColorOxfordBlue", + "html": "#000055", + "name": "Oxford Blue" + }, + { + "gcolour": "GColorRoseVale", + "html": "#AA5555", + "name": "Rose Vale" + }, + { + "gcolour": "GColorCadetBlue", + "html": "#55AAAA", + "name": "Cadet Blue" + }, + { + "gcolour": "GColorFashionMagenta", + "html": "#FF00AA", + "name": "Fashion Magenta" + }, + { + "gcolour": "GColorMelon", + "html": "#FFAAAA", + "name": "Melon" + }, + { + "gcolour": "GColorJazzberryJam", + "html": "#AA0055", + "name": "Jazzberry Jam" + }, + { + "gcolour": "GColorPurpureus", + "html": "#AA55AA", + "name": "Purpureus" + }, + { + "gcolour": "GColorImperialPurple", + "html": "#550055", + "name": "Imperial Purple" + }, + { + "gcolour": "GColorDarkGreen", + "html": "#005500", + "name": "Dark Green (X11)" + }, + { + "gcolour": "GColorBlue", + "html": "#0000FF", + "name": "Blue" + }, + { + "gcolour": "GColorLiberty", + "html": "#5555AA", + "name": "Liberty" + }, + { + "gcolour": "GColorDarkCandyAppleRed", + "html": "#AA0000", + "name": "Dark Candy Apple Red" + }, + { + "gcolour": "GColorMayGreen", + "html": "#55AA55", + "name": "May Green" + }, + { + "gcolour": "GColorVividViolet", + "html": "#AA00FF", + "name": "Vivid Violet" + }, + { + "gcolour": "GColorRajah", + "html": "#FFAA55", + "name": "Rajah" + }, + { + "gcolour": "GColorBrilliantRose", + "html": "#FF55AA", + "name": "Brilliant Rose" + }, + { + "gcolour": "GColorLightGray", + "html": "#AAAAAA", + "name": "Light Gray" + }, + { + "gcolour": "GColorVeryLightBlue", + "html": "#5555FF", + "name": "Very Light Blue" + }, + { + "gcolour": "GColorBulgarianRose", + "html": "#550000", + "name": "Bulgarian Rose" + }, + { + "gcolour": "GColorGreen", + "html": "#00FF00", + "name": "Green" + }, + { + "gcolour": "GColorWindsorTan", + "html": "#AA5500", + "name": "Windsor Tan" + }, + { + "gcolour": "GColorJaegerGreen", + "html": "#00AA55", + "name": "Jaeger Green" + }, + { + "gcolour": "GColorDarkGray", + "html": "#555555", + "name": "Dark Gray" + }, + { + "gcolour": "GColorOrange", + "html": "#FF5500", + "name": "Orange" + }, + { + "gcolour": "GColorBlueMoon", + "html": "#0055FF", + "name": "Blue Moon" + }, + { + "gcolour": "GColorBlack", + "html": "#000000", + "name": "Black" + }, + { + "gcolour": "GColorCyan", + "html": "#00FFFF", + "name": "Cyan" + }, + { + "gcolour": "GColorPastelYellow", + "html": "#FFFFAA", + "name": "Pastel Yellow" + }, + { + "gcolour": "GColorLimerick", + "html": "#AAAA00", + "name": "Limerick" + }, + { + "gcolour": "GColorCobaltBlue", + "html": "#0055AA", + "name": "Cobalt Blue" + }, + { + "gcolour": "GColorDukeBlue", + "html": "#0000AA", + "name": "Duke Blue" + }, + { + "gcolour": "GColorShockingPink", + "html": "#FF55FF", + "name": "Shocking Pink (Crayola)" + }, + { + "gcolour": "GColorScreaminGreen", + "html": "#55FF55", + "name": "Screamin' Green" + }, + { + "gcolour": "GColorRed", + "html": "#FF0000", + "name": "Red" + }, + { + "gcolour": "GColorKellyGreen", + "html": "#55AA00", + "name": "Kelly Green" + }, + { + "gcolour": "GColorVividCerulean", + "html": "#00AAFF", + "name": "Vivid Cerulean" + }, + { + "gcolour": "GColorLavenderIndigo", + "html": "#AA55FF", + "name": "Lavender Indigo" + }, + { + "gcolour": "GColorInchworm", + "html": "#AAFF55", + "name": "Inchworm" + }, + { + "gcolour": "GColorMalachite", + "html": "#00FF55", + "name": "Malachite" + }, + { + "gcolour": "GColorMediumAquamarine", + "html": "#55FFAA", + "name": "Medium Aquamarine" + }, + { + "gcolour": "GColorYellow", + "html": "#FFFF00", + "name": "Yellow" + }, + { + "gcolour": "GColorMagenta", + "html": "#FF00FF", + "name": "Magenta" + }, + { + "gcolour": "GColorCeleste", + "html": "#AAFFFF", + "name": "Celeste" + }, + { + "gcolour": "GColorRichBrilliantLavender", + "html": "#FFAAFF", + "name": "Rich Brilliant Lavender" + }, + { + "gcolour": "GColorBabyBlueEyes", + "html": "#AAAAFF", + "name": "Baby Blue Eyes" + }, + { + "gcolour": "GColorMidnightGreen", + "html": "#005555", + "name": "Midnight Green (Eagle Green)" + }, + { + "gcolour": "GColorPurple", + "html": "#AA00AA", + "name": "Purple" + }, + { + "gcolour": "GColorWhite", + "html": "#FFFFFF", + "name": "White" + }, + { + "gcolour": "GColorMediumSpringGreen", + "html": "#00FFAA", + "name": "Medium Spring Green" + }, + { + "gcolour": "GColorIcterine", + "html": "#FFFF55", + "name": "Icterine" + }, + { + "gcolour": "GColorSunsetOrange", + "html": "#FF5555", + "name": "Sunset Orange" + }, + { + "gcolour": "GColorBrass", + "html": "#AAAA55", + "name": "Brass" + }, + { + "gcolour": "GColorIslamicGreen", + "html": "#00AA00", + "name": "Islamic Green" + } +]; +})(); diff --git a/ide/static/ide/js/ib/ib.js b/ide/static/ide/js/ib/ib.js index 397286b4..ab84684a 100644 --- a/ide/static/ide/js/ib/ib.js +++ b/ide/static/ide/js/ib/ib.js @@ -9,11 +9,12 @@ * @constructor * @extends {Backbone.Events} */ - function IB(canvasPane, propertyPane, toolkitPane, layerPane, source) { + function IB(canvasPane, propertyPane, toolkitPane, layerPane, settingsPane, source) { var mCanvas; var mPropertyView; var mToolkit; var mLayerListView; + var mSettingsForm; var mSource = ''; var self = this; @@ -24,11 +25,14 @@ mCanvas.on('selection', handleSelection); mToolkit = new IB.Toolkit(toolkitPane, mCanvas); mToolkit.renderList(); + mSettingsForm = new IB.SettingsForm(settingsPane, this); + mSettingsForm.render(); + mSettingsForm.on('refresh', _.bind(mCanvas.refresh, mCanvas)); mLayerListView = new IB.LayerListView(layerPane, mCanvas); mCanvas.on('changed', handleChange); handleSelection(null); CloudPebble.Analytics.addEvent("cloudpebble_ib_displayed", null, null, ['cloudpebble']); - } + }; /** * Handles changing the selection. If a layer is passed, selects that. If null, selects the window. @@ -85,9 +89,13 @@ propertyPane.empty(); toolkitPane.empty(); layerPane.empty(); + mSettingsForm.empty(); init(); }; - + if (!IB.colourMode) { + IB.colourEnabled = (CloudPebble.ProjectInfo.sdk_version == "3"); + IB.colourMode = (CloudPebble.ProjectInfo.sdk_version == "3" ? IB.ColourModes.Colour : IB.ColourModes.Monochrome); + } init(); } window.IB = IB; diff --git a/ide/static/ide/js/ib/layers/actionbarlayer.js b/ide/static/ide/js/ib/layers/actionbarlayer.js index 7761444a..ef6f6c90 100644 --- a/ide/static/ide/js/ib/layers/actionbarlayer.js +++ b/ide/static/ide/js/ib/layers/actionbarlayer.js @@ -11,7 +11,7 @@ IB.Layer.call(this, canvas, id); _.extend(this._properties, { - bg: new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourBlack), + bg: new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourBlack, true), icon_up: new IB.Properties.Bitmap(gettext("Top icon"), ""), icon_select: new IB.Properties.Bitmap(gettext("Middle icon"), ""), icon_down: new IB.Properties.Bitmap(gettext("Bottom icon"), "") @@ -32,8 +32,15 @@ this._properties['icon_' + it].on('change', _.partial(this._handleIconChange, it), this); }, this); - this.setSize(20, 146); - this.setPos(124, 3); + if (CloudPebble.ProjectInfo.sdk_version == "3") { + this.setSize(30, 168); + this.setPos(114, 0); + } + else { + this.setSize(20, 146); + this.setPos(124, 3); + } + this._size.lock(); this._pos.lock(); }; @@ -48,7 +55,8 @@ this._node.css({ 'background-color': this._backgroundColour.getValue().css }); - var invertIcons = (this._backgroundColour.getValue() != IB.ColourWhite); + var monoBgColour = this._backgroundColour.getValue(IB.ColourModes.Monochrome); + var invertIcons = (monoBgColour !== IB.ColourWhite && IB.colourMode == IB.ColourModes.Monochrome); _.each(this._icon_nodes, function(node, it) { if(invertIcons) { node.addClass('ib-invert'); @@ -71,9 +79,10 @@ this._ID + " = action_bar_layer_create();", "action_bar_layer_add_to_window(" + this._ID + ", s_window);" ]; - if(this._backgroundColour != IB.ColourBlack) { + + if(!this._backgroundColour.fullyEquals(IB.ColourBlack)) { init.push("action_bar_layer_set_background_color(" - + this._ID + ", " + this._backgroundColour.getValue().name + ");"); + + this._ID + ", " + this._backgroundColour.generateCode() + ");"); } _.each(BUTTONS, function(it) { var icon = this._icons[it].getValue(); @@ -93,7 +102,7 @@ _.each(properties, function(values, property) { switch(property) { case "action_bar_layer_set_background_color": - this._backgroundColour.setValue(IB.ColourMap[values[0][1]]); + this._backgroundColour.setValue(values[0][1]); break; case "action_bar_layer_set_icon": _.each(values, function(group) { diff --git a/ide/static/ide/js/ib/layers/bitmaplayer.js b/ide/static/ide/js/ib/layers/bitmaplayer.js index e4815142..c80aef11 100644 --- a/ide/static/ide/js/ib/layers/bitmaplayer.js +++ b/ide/static/ide/js/ib/layers/bitmaplayer.js @@ -9,7 +9,7 @@ IB.BitmapLayer = function(canvas, id) { IB.Layer.call(this, canvas, id); this._resource = new IB.Properties.Bitmap(gettext("Image"), ''); - this._bg_colour = new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourClear); + this._bg_colour = new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourClear, true); this._has_changed_image = false; this._node.addClass('ib-bitmaplayer'); this.setSize(40, 40); @@ -64,8 +64,8 @@ if(this._resource.getValue()) { init.push("bitmap_layer_set_bitmap(" + this._ID + ", " + this._canvas.getResources().getResource(this._resource.getValue()) + ");"); } - if(this._bg_colour.getValue() != IB.ColourClear) { - init.push("bitmap_layer_set_background_color(" + this._ID + ", " + this._bg_colour.getValue().name + ");"); + if(!this._bg_colour.fullyEquals(IB.ColourClear)) { + init.push("bitmap_layer_set_background_color(" + this._ID + ", " + this._bg_colour.generateCode() + ");"); } return init; }, @@ -77,7 +77,7 @@ _.each(properties, function(values, property) { switch(property) { case "bitmap_layer_set_background_color": - this.setBackgroundColour(IB.ColourMap[values[0][1]]); + this.setBackgroundColour(values[0][1]); break; case "bitmap_layer_set_bitmap": if(mappings[values[0][1]]) { diff --git a/ide/static/ide/js/ib/layers/inverterlayer.js b/ide/static/ide/js/ib/layers/inverterlayer.js index 6fc69889..cf474979 100644 --- a/ide/static/ide/js/ib/layers/inverterlayer.js +++ b/ide/static/ide/js/ib/layers/inverterlayer.js @@ -14,6 +14,7 @@ IB.InverterLayer.className = 'InverterLayer'; IB.InverterLayer.prototype = Object.create(IB.Layer.prototype); IB.InverterLayer.description = gettext("Inverts the colours of the rectangle behind it. Layers in front are unaffected."); + IB.InverterLayer.allowedSDKs = [2]; _.extend(IB.InverterLayer.prototype, { constructor: IB.InverterLayer, // Rendering works by duplicating all layers *below* the current layer as children of our node, diff --git a/ide/static/ide/js/ib/layers/textlayer.js b/ide/static/ide/js/ib/layers/textlayer.js index 9afb9c3e..45ab044f 100644 --- a/ide/static/ide/js/ib/layers/textlayer.js +++ b/ide/static/ide/js/ib/layers/textlayer.js @@ -14,8 +14,8 @@ _.extend(this._properties, { text: new IB.Properties.Text(gettext("Text"), pgettext("sample text", "Text layer")), font: new IB.Properties.Font(gettext("Font"), "GOTHIC_14_BOLD"), - fg: new IB.Properties.Colour(gettext("Text colour"), IB.ColourBlack), - bg: new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourWhite), + fg: new IB.Properties.Colour(gettext("Text colour"), IB.ColourBlack, false), + bg: new IB.Properties.Colour(pgettext("background colour", "Background"), IB.ColourWhite, true), align: new IB.Properties.MultipleChoice(pgettext("horizontal text positioning", "Alignment"), { "GTextAlignmentLeft": gettext("Left"), "GTextAlignmentCenter": gettext("Centre"), @@ -73,11 +73,11 @@ }, generateInitialiser: function() { var init = [this._ID + " = text_layer_create(" + this.generateRect() + ");"]; - if(this._backgroundColour.getValue() != IB.ColourWhite) { - init.push("text_layer_set_background_color(" + this._ID + ", " + this._backgroundColour.getValue().name + ");"); + if(!this._backgroundColour.fullyEquals(IB.ColourWhite)) { + init.push("text_layer_set_background_color(" + this._ID + ", " + this._backgroundColour.generateCode() + ");"); } - if(this._textColour.getValue() != IB.ColourBlack) { - init.push("text_layer_set_text_color(" + this._ID + ", " + this._textColour.getValue().name + ");"); + if(!this._textColour.fullyEquals(IB.ColourBlack)) { + init.push("text_layer_set_text_color(" + this._ID + ", " + this._textColour.generateCode() + ");"); } if(this._text.getValue() != "") { init.push("text_layer_set_text(" + this._ID + ", \"" + IB.escapeCString(this.getText()) + "\");"); @@ -98,10 +98,10 @@ _.each(properties, function(values, property) { switch(property) { case "text_layer_set_background_color": - this.setBackgroundColour(IB.ColourMap[values[0][1]]); + this.setBackgroundColour(values[0][1]); break; case "text_layer_set_text_color": - this.setTextColour(IB.ColourMap[values[0][1]]); + this.setTextColour(values[0][1]); break; case "text_layer_set_text": this.setText(JSON.parse(values[0][0])); diff --git a/ide/static/ide/js/ib/properties.js b/ide/static/ide/js/ib/properties.js index 6929566f..5415153c 100644 --- a/ide/static/ide/js/ib/properties.js +++ b/ide/static/ide/js/ib/properties.js @@ -17,6 +17,7 @@ this._value = value; this._node = this._generateNode(); this._locked = false; + this._labelClass = null; _.extend(this, Backbone.Events); }; IB.Properties.Property.prototype = { @@ -26,6 +27,12 @@ getName: function() { return this._name; }, + /** + * @returns {*} The the class name to add to the property's label. + */ + getLabelClass: function() { + return this._labelClass; + }, /** * @returns {*} The value of the property. */ @@ -188,23 +195,118 @@ * @constructor * @extends {IB.Properties.Property} */ - IB.Properties.Colour = function(name, value) { - Property.call(this, name, value); + IB.Properties.Colour = function(name, value, is_fill) { + this.is_fill = !!is_fill; + Property.call(this, name, this._makeColours(value)); + if (IB.colourEnabled) { + this._labelClass = 'ib-colour-label'; + } }; IB.Properties.Colour.prototype = Object.create(_super); IB.Properties.Colour.prototype.constructor = IB.Properties.Colour; _.extend(IB.Properties.Colour.prototype, { + _makeColours: function(value) { + if (_.isString(value)) { + value = IB.ColourMap[value]; + } + if (_.isArray(value)) { + if (value[0] == "PBL_IF_COLOR_ELSE") { + value = _.map(value.slice(1), function(c) { + return IB.ColourMap[c]; + }); + } + } + else { + // Assume value is a Colour object + value = [value, value]; + } + return value; + }, setValue: function(value) { - _super.setValue.call(this, value); - this._node.val(this._value.name); + var new_value = this._makeColours(value); + _super.setValue.call(this, new_value); + this._bwNode.val(this._value[IB.ColourModes.Monochrome].name); + this._colourNode.val(this._value[IB.ColourModes.Colour].name); + this._setColourCSS(); + }, + getValue: function(index) { + var value = _super.getValue.call(this); + return (_.isArray(value) ? (_.isFinite(index) ? value[index] : value[IB.colourMode]) : value); + }, + /** + * Returns true if all variants of the colour are equal to a given one + * @param colour the colour co compare to + * @returns {boolean} + */ + fullyEquals: function(colour) { + var uniq = _.uniq(this._value); + return (uniq.length == 1 && uniq[0] == colour); + }, + /** + * Generate the C expression representing this property. + * @returns {string} + */ + generateCode: function() { + if (_.uniq(this._value).length == 1) { + return this._value[0].name; + } else { + return interpolate("PBL_IF_COLOR_ELSE(%s, %s)", [this._value[0].name, this._value[1].name]); + } + }, + /** + * Refresh the colour picker box for this property + * @private + */ + _setColourCSS: function() { + if (this._value[0]) { + var stripes = 'repeating-linear-gradient(45deg, #aaa, #aaa 4px, #fff 5px, #fff 10px)'; + var is_clear = this._value[IB.ColourModes.Colour] == IB.ColourClear; + var css = (is_clear ? stripes : this._value[IB.ColourModes.Colour].css); + this._colourNode.siblings().find(".value").css('background', css); + } }, _generateNode: function() { - return $('') + .append(mono_options) + .val(this._value[IB.ColourModes.Monochrome].name) .change(_.bind(this._handleChange, this)); + + if (IB.colourEnabled) { + element = $(interpolate('' + + '' + + '' + + '
%s%s
', [gettext("Colour Watches"), gettext("B/W Watches")])); + var tr = element.find('tbody tr'); + var td = $("").appendTo(tr); + var div = $('
').appendTo(td); + this._colourNode = $('') + .change(_.bind(this._handleChange, this)) + .val(this._value[IB.ColourModes.Colour].name) + .appendTo(div); + this._bwNode.appendTo("").parent().appendTo(tr); + + var self = this; + setTimeout(function() { + self._colourNode.pebbleColourPicker({ + value_mapping: function(value) { + if (value == "transparent") { + return "GColorClear"; + } + else { + return _.findWhere(IB.ColourMap, {css: value}); + } + } + }); + self._setColourCSS(); + }, 0); + } + else { + this._colourNode = this._bwNode; + element = this._bwNode; + } + return element; }, _createColour: function(colour) { return $('