Browse DevX
Sign up for e-mail newsletters from DevX


Nano-Sheets: A Small But Mighty Spreadsheet Engine in REBOL  : Page 3

Even in today's big-computing environment, not everything useful has to be big. This article shows you how to build a tiny and basic—but powerful—GUI spreadsheet engine in REBOL, using fewer than 1500 bytes of code.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Analyzing the Code
The Nano-Sheets code begins with a few definitions that control the size of the cells and the overall sheet itself. The cell size is in pixels; the sheet size in cells. They are both REBOL pair! values.

csize: 100x20 size: 8x16

There are a few helper functions to make things easier and clearer in the main generation loop. The meaning of col-lbl and cell-name should be pretty obvious, but mk-var might not be; it creates a variable name dynamically so you don't have to declare variables statically for every cell.

col-lbl: func [col] [form to char! 64 + col] cell-name: func [x y] [join col-lbl x y] mk-var: func [x y] [to lit-word! cell-name x y]

The sheet definition starts out with some static elements that set the spacing and layout orientation, and then define a couple of styles used in the UI, much as you might use CSS to define styles for use in an HTML document.

sheet: copy [ space 1x1 across style cell field csize edge none with [formula: none] [enter face compute face/para/scroll: 0x0] style label text csize white black bold center ]

Next is the real magic. The two nested loops add elements to the sheet layout spec. If you've ever written a CGI app to dynamically generate a table in HTML, you'll recognize that this is the same concept. The big difference is that these items will become active cells when they are rendered, and will be bound to a variable that represents them for use in formulas.

repeat y 1 + size/y [ repend sheet ['label (csize / 2x1) either 1 = y [""] [form y - 1]] repeat x size/x [ append sheet compose/deep either 1 = y [[label (col-lbl x)]] [ [cell with [var: (mk-var x y - 1)]] ] ] append sheet 'return ]

Setting Cell Values and Triggering Recalculations
The spreadsheet calls the enter function when a cell loses focus. Its job is to evaluate what a user entered, decide if it's a formula, and set the value for the variable bound to the cell. Formulas, as in other spreadsheets, are identified by a leading equal sign (=). The spreadsheet coerces text entered in the cell to the most appropriate internal data type, so calculations operate in an intuitive way (e.g. $100 * 3 = $300).

enter: func [face /local data] [ if empty? face/text [exit] set face/var face/text data: either #"=" = face/text/1 [next face/text][face/text] if error? try [data: load data] [exit] if find [integer! decimal! money! time! date! tuple! pair!] type?/word :data [ set face/var data exit ] if face/text/1 = #"=" [face/formula: :data] ]

Thanks for your registration, follow us on our social networks to keep up-to-date