Skip to content

Commit

Permalink
Move bar code, test border style
Browse files Browse the repository at this point in the history
  • Loading branch information
Erik Corry committed Nov 28, 2023
1 parent 43451b5 commit 082021d
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 153 deletions.
136 changes: 136 additions & 0 deletions src/bar_code.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright (C) 2023 Toitware ApS. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.
import font show Font

import .common
import .element show CustomElement
import .style

EAN_13_QUIET_ZONE_WIDTH ::= 9
EAN_13_START_WIDTH ::= 3
EAN_13_MIDDLE_WIDTH ::= 5
EAN_13_DIGIT_WIDTH ::= 7
EAN_13_BOTTOM_SPACE ::= 5
EAN_13_WIDTH ::= 2 * EAN_13_QUIET_ZONE_WIDTH + 2 * EAN_13_START_WIDTH + EAN_13_MIDDLE_WIDTH + 12 * EAN_13_DIGIT_WIDTH
EAN_13_HEIGHT ::= 83
// Encoding of L digits. R digits are the bitwise-not of this and G digits are
// the R digits in reverse order.
EAN_13_L_CODES_ ::= [0x0d, 0x19, 0x13, 0x3d, 0x23, 0x31, 0x2f, 0x3b, 0x37, 0x0b]
EAN_13_G_CODES_ ::= [0x27, 0x33, 0x1b, 0x21, 0x1d, 0x39, 0x05, 0x11, 0x09, 0x17]
// Encoding of the first (invisible) digit.
EAN_13_FIRST_CODES_ ::= [0x00, 0x0b, 0x0d, 0x0e, 0x13, 0x19, 0x1c, 0x15, 0x16, 0x1a]

// Element that draws a standard EAN-13 bar code. TODO: Other scales.
class BarCodeEanElement extends CustomElement:
color_/int? := 0
background_ := 0xff
sans10_ ::= Font.get "sans10"
number_height_ := EAN_13_BOTTOM_SPACE

type -> string: return "bar-code-ean"

set_attribute key/string value -> none:
if key == "color":
if color_ != value:
invalidate
color_ = value
else:
super key value

code_ := ? // 13 digit code as a string.
code= value/string -> none:
if value != code_: invalidate
code_ = value

code -> string: return code_

/**
$code_: The 13 digit product code.
$x: The left edge of the barcode in the coordinate system of the transform.
$y: The top edge of the barcode in the coordinate system of the transform.
Use $set_styles to set the background to white and the color to black.
*/
constructor .code_/string --x/int?=null --y/int?=null:
// The numbers go below the bar code in a way that depends on the size
// of the digits, so we need to take that into account when calculating
// the bounding box.
number_height_ = (sans10_.text_extent "8")[1]
height := EAN_13_HEIGHT + number_height_ - EAN_13_BOTTOM_SPACE
w := EAN_13_WIDTH
h := height + 1
super --x=x --y=y --w=w --h=h

l_ digit:
return EAN_13_L_CODES_[digit & 0xf]

g_ digit:
return EAN_13_G_CODES_[digit & 0xf]

r_ digit:
return (l_ digit) ^ 0x7f

// Make a white background behind the bar code and draw the digits along the bottom.
draw_background_ canvas/Canvas:
if not (x and y): return
Background.draw background_ canvas x_ y_ w h

// Bar code coordinates.
text_x := x + EAN_13_QUIET_ZONE_WIDTH + EAN_13_START_WIDTH
text_y := y + EAN_13_HEIGHT + number_height_ - EAN_13_BOTTOM_SPACE + 1

canvas.text (x + 1) text_y --text=code_[..1] --color=color_ --font=sans10_

code_[1..7].split "":
if it != "":
canvas.text text_x text_y --text=it --color=color_ --font=sans10_
text_x += EAN_13_DIGIT_WIDTH
text_x += EAN_13_MIDDLE_WIDTH - 1
code_[7..13].split "":
if it != "":
canvas.text text_x text_y --text=it --color=color_ --font=sans10_
text_x += EAN_13_DIGIT_WIDTH
marker_width := (sans10_.text_extent ">")[0]
text_x += EAN_13_START_WIDTH + EAN_13_QUIET_ZONE_WIDTH - marker_width
canvas.text text_x text_y --text=">" --color=color_ --font=sans10_

// Redraw routine.
draw canvas/Canvas:
if not (x and y): return
if (canvas.bounds_analysis x y w h) == Canvas.ALL_OUTSIDE: return
draw_background_ canvas

x := x_ + EAN_13_QUIET_ZONE_WIDTH
top := y_
long_height := EAN_13_HEIGHT
short_height := EAN_13_HEIGHT - EAN_13_BOTTOM_SPACE
// Start bars: 101.
canvas.rectangle x top --w=1 --h=long_height --color=color_
canvas.rectangle x + 2 top --w=1 --h=long_height --color=color_
x += 3
first_code := EAN_13_FIRST_CODES_[code_[0] & 0xf]
// Left digits using the L or G mapping.
for i := 1; i < 7; i++:
digit := code_[i]
code := ((first_code >> (6 - i)) & 1) == 0 ? (l_ digit) : (g_ digit)
for b := 6; b >= 0; b--:
if ((1 << b) & code) != 0:
canvas.rectangle x top --w=1 --h=short_height --color=color_
x++
// Middle bars: 01010
canvas.rectangle x + 1 top --w=1 --h=long_height --color=color_
canvas.rectangle x + 3 top --w=1 --h=long_height --color=color_
x += 5
// Left digits using the R mapping.
for i := 7; i < 13; i++:
digit := code_[i]
code := r_ digit
for b := 6; b >= 0; b--:
if ((1 << b) & code) != 0:
canvas.rectangle x top --w=1 --h=short_height --color=color_
x++
// End bars: 101.
canvas.rectangle x top --w=1 --h=long_height --color=color_
canvas.rectangle x + 2 top --w=1 --h=long_height --color=color_
18 changes: 0 additions & 18 deletions src/bar_code_impl_.toit

This file was deleted.

157 changes: 28 additions & 129 deletions src/element.toit
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import .one_byte as one_byte
import .style
import .style show RoundedCornerOpacity_
import .common
import .bar_code_impl_
import font show Font
import math

Expand Down Expand Up @@ -49,6 +48,8 @@ abstract class Element extends ElementOrTexture_ implements Window:
classes.add element_class
background_=background
border_=border
if children: children.do: | child/Element |
child.change_tracker = this

get_element_by_id id/string:
if id == this.id: return this
Expand Down Expand Up @@ -152,6 +153,12 @@ abstract class Element extends ElementOrTexture_ implements Window:
if background_ != value:
invalidate
background_ = value
invalidate
else if key == "border":
if border_ != value:
invalidate
border_ = value
invalidate

abstract type -> string

Expand Down Expand Up @@ -215,6 +222,8 @@ class Div extends Element:
w = value
else if key == "height":
h = value
else:
super key value

draw canvas/Canvas -> none:
if children:
Expand Down Expand Up @@ -401,140 +410,19 @@ A superclass for elements that can draw themselves. Override the
and $h methods/fields are used to determine the size of the element
for redrawing purposes.
Drawing operations are not automatically clipped to w and h, but if you
draw outside the area then partial screen updates will be broken.
Drawing operations are automatically clipped to w and h.
*/
abstract class CustomElement extends Element:
abstract class CustomElement extends ClippingDiv:
abstract w -> int?
abstract h -> int?

constructor --x/int?=null --y/int?=null:
super --x=x --y=y
constructor --x/int?=null --y/int?=null --w/int?=null --h/int?=null:
super --x=x --y=y --w=w --h=h

invalidate:
if change_tracker and x and y and w and h:
change_tracker.child_invalidated_element x y w h

// Element that draws a standard EAN-13 bar code. TODO: Other scales.
class BarCodeEanElement extends CustomElement:
w/int
h/int
color_/int? := 0
background_ := 0xff
sans10_ ::= Font.get "sans10"
number_height_ := EAN_13_BOTTOM_SPACE

type -> string: return "bar-code-ean"

set_attribute key/string value -> none:
if key == "color":
if color_ != value:
invalidate
color_ = value
else if key == "background":
if background_ != value:
invalidate
background_ = value

min_w: return w
min_h: return h

code_ := ? // 13 digit code as a string.
code= value/string -> none:
if value != code_: invalidate
code_ = value

code -> string: return code_

/**
$code_: The 13 digit product code.
$x: The left edge of the barcode in the coordinate system of the transform.
$y: The top edge of the barcode in the coordinate system of the transform.
Use $set_styles to set the background to white and the color to black.
*/
constructor .code_/string x/int?=null y/int?=null:
// The numbers go below the bar code in a way that depends on the size
// of the digits, so we need to take that into account when calculating
// the bounding box.
number_height_ = (sans10_.text_extent "8")[1]
height := EAN_13_HEIGHT + number_height_ - EAN_13_BOTTOM_SPACE
w = EAN_13_WIDTH
h = height + 1
super --x=x --y=y

l_ digit:
return EAN_13_L_CODES_[digit & 0xf]

g_ digit:
return EAN_13_G_CODES_[digit & 0xf]

r_ digit:
return (l_ digit) ^ 0x7f

// Make a white background behind the bar code and draw the digits along the bottom.
draw_background_ canvas/Canvas:
if not (x and y): return
Background.draw background_ canvas x_ y_ w h

// Bar code coordinates.
text_x := x + EAN_13_QUIET_ZONE_WIDTH + EAN_13_START_WIDTH
text_y := y + EAN_13_HEIGHT + number_height_ - EAN_13_BOTTOM_SPACE + 1

canvas.text (x + 1) text_y --text=code_[..1] --color=color_ --font=sans10_

code_[1..7].split "":
if it != "":
canvas.text text_x text_y --text=it --color=color_ --font=sans10_
text_x += EAN_13_DIGIT_WIDTH
text_x += EAN_13_MIDDLE_WIDTH - 1
code_[7..13].split "":
if it != "":
canvas.text text_x text_y --text=it --color=color_ --font=sans10_
text_x += EAN_13_DIGIT_WIDTH
marker_width := (sans10_.text_extent ">")[0]
text_x += EAN_13_START_WIDTH + EAN_13_QUIET_ZONE_WIDTH - marker_width
canvas.text text_x text_y --text=">" --color=color_ --font=sans10_

// Redraw routine.
draw canvas/Canvas:
if not (x and y): return
if (canvas.bounds_analysis x y w h) == Canvas.ALL_OUTSIDE: return
draw_background_ canvas

x := x_ + EAN_13_QUIET_ZONE_WIDTH
top := y_
long_height := EAN_13_HEIGHT
short_height := EAN_13_HEIGHT - EAN_13_BOTTOM_SPACE
// Start bars: 101.
canvas.rectangle x top --w=1 --h=long_height --color=color_
canvas.rectangle x + 2 top --w=1 --h=long_height --color=color_
x += 3
first_code := EAN_13_FIRST_CODES_[code_[0] & 0xf]
// Left digits using the L or G mapping.
for i := 1; i < 7; i++:
digit := code_[i]
code := ((first_code >> (6 - i)) & 1) == 0 ? (l_ digit) : (g_ digit)
for b := 6; b >= 0; b--:
if ((1 << b) & code) != 0:
canvas.rectangle x top --w=1 --h=short_height --color=color_
x++
// Middle bars: 01010
canvas.rectangle x + 1 top --w=1 --h=long_height --color=color_
canvas.rectangle x + 3 top --w=1 --h=long_height --color=color_
x += 5
// Left digits using the R mapping.
for i := 7; i < 13; i++:
digit := code_[i]
code := r_ digit
for b := 6; b >= 0; b--:
if ((1 << b) & code) != 0:
canvas.rectangle x top --w=1 --h=short_height --color=color_
x++
// End bars: 101.
canvas.rectangle x top --w=1 --h=long_height --color=color_
canvas.rectangle x + 2 top --w=1 --h=long_height --color=color_

/**
A ClippingDiv is like a div, but it clips any draws inside of it. It can
have a shadow or other drawing outside its raw x y w h area, called the
Expand All @@ -543,7 +431,7 @@ For style purposes it has the type "div", not "clipping-div".
Because it has clipping and compositing, it can have more interesting borders
like rounded corners.
*/
class ClippingDiv extends Div implements Window:
class ClippingDiv extends Div:
/**
Calls the block with x, y, w, h, which includes the decoration.
*/
Expand Down Expand Up @@ -572,8 +460,19 @@ class ClippingDiv extends Div implements Window:
if opacity is not ByteArray: return false
return opacity.size == 1 and opacity[0] == 0xff

constructor --x/int?=null --y/int?=null --w/int?=null --h/int?=null --background=null --border/Border?=null:
super --x=x --y=y --w=w --h=h --background=background --border=border
constructor
--x/int?=null
--y/int?=null
--w/int?=null
--h/int?=null
--style/Style?=null
--element_class/string?=null
--classes/List?=null
--id/string?=null
--background=null
--border/Border?=null
children/List?=null:
super --x=x --y=y --w=w --h=h --style=style --element_class=element_class --classes=classes --id=id --background=background --border=border children

// After the textures under us have drawn themselves, we draw on top.
draw canvas/Canvas -> none:
Expand Down
Loading

0 comments on commit 082021d

Please sign in to comment.