-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add sliders/level meters.
- Loading branch information
Erik Corry
authored
Dec 7, 2023
1 parent
2b36b1d
commit 176d22a
Showing
3 changed files
with
225 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// 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 .common | ||
import .element | ||
import .style | ||
|
||
/** | ||
A vertical slider that can indicate a value between a minimum and a maxiumum. | ||
You can provide a background to draw when the slider is above a certain level, | ||
and a different one for when the slider is below that level. If either | ||
background is omitted the slider is transparent in that section. | ||
Currently no thumb is drawn, so the indication is the boundary between | ||
the two backgrounds. | ||
*/ | ||
class Slider extends CustomElement: | ||
value_/num? := ? | ||
min_/num? := ? | ||
max_/num? := ? | ||
background_lo_ := ? | ||
background_hi_ := ? | ||
horizontal_ := ? | ||
|
||
thumb_min_/int | ||
thumb_max_/int? | ||
boundary_/int := 0 | ||
|
||
type -> string: return "vertical-slider" | ||
|
||
constructor --x/int?=null --y/int?=null --w/int?=null --h/int?=null --background-hi=null --background-lo=null --value/num?=null --min/num?=0 --max/num?=100 --thumb_min/int=0 --thumb_max/int?=null --horizontal/bool=false: | ||
value_ = value | ||
min_ = min | ||
max_ = max | ||
background_lo_ = background_lo | ||
background_hi_ = background_hi | ||
thumb_min_ = thumb_min | ||
thumb_max_ = thumb_max | ||
horizontal_ = horizontal | ||
super --x=x --y=y --w=w --h=h | ||
recalculate_ | ||
|
||
thumb_max: return thumb_max_ or (horizontal_ ? w : h) | ||
|
||
recalculate_ -> none: | ||
if not (min_ and max_ and value_ and h): return | ||
if (min_ == max_): return | ||
value_ = max value_ min_ | ||
value_ = min value_ max_ | ||
old_boundary := boundary_ | ||
boundary_ = ((value_ - min_).to_float / (max_ - min_) * (thumb_max - thumb_min_) + 0.1).to_int + thumb_min_ | ||
if boundary_ != old_boundary: | ||
top := max old_boundary boundary_ | ||
bottom := min old_boundary boundary_ | ||
if horizontal_: | ||
invalidate | ||
--x = x + w - top | ||
--w = top - bottom | ||
else: | ||
invalidate | ||
--y = y + h - top | ||
--h = top - bottom | ||
|
||
h= value/int -> none: | ||
if value != h: | ||
invalidate | ||
h_ = value | ||
recalculate_ | ||
invalidate | ||
|
||
w= value/int -> none: | ||
if value != w: | ||
invalidate | ||
w_ = value | ||
recalculate_ | ||
invalidate | ||
|
||
custom_draw canvas/Canvas -> none: | ||
blend := false | ||
if background_lo_ and boundary_ > thumb_min_: | ||
analysis := ? | ||
if horizontal_: | ||
analysis = canvas.bounds_analysis 0 0 (w - boundary_) h | ||
else: | ||
analysis = canvas.bounds_analysis 0 0 w (h - boundary_) | ||
if analysis != Canvas.DISJOINT: | ||
if analysis == Canvas.CANVAS_IN_AREA or analysis == Canvas.COINCIDENT: | ||
background_lo_.draw canvas 0 0 w h --autocropped | ||
else: | ||
blend = true | ||
if background_hi_ and boundary_ < thumb_max: | ||
analysis := ? | ||
if horizontal_: | ||
analysis = canvas.bounds_analysis (w - boundary_) 0 w h | ||
else: | ||
analysis = canvas.bounds_analysis 0 (h - boundary_) w h | ||
if analysis != Canvas.DISJOINT: | ||
if analysis == Canvas.CANVAS_IN_AREA or analysis == Canvas.COINCIDENT: | ||
background_hi_.draw canvas 0 0 w h --autocropped | ||
else: | ||
blend = true | ||
if not blend: return | ||
|
||
lo_alpha := background_lo_ ? canvas.make_alpha_map : ClippingDiv.ALL_TRANSPARENT | ||
hi_alpha := background_hi_ ? canvas.make_alpha_map : ClippingDiv.ALL_TRANSPARENT | ||
lo := canvas.create_similar | ||
hi := canvas.create_similar | ||
|
||
if background_lo_: | ||
if horizontal_: | ||
lo_alpha.rectangle 0 0 --w=(w - boundary_) --h=h --color=0xff | ||
else: | ||
lo_alpha.rectangle 0 0 --w=w --h=(h - boundary_) --color=0xff | ||
Background.draw background_lo_ lo 0 0 w h --autocropped | ||
if background_hi_: | ||
if horizontal_: | ||
hi_alpha.rectangle (w - boundary_) 0 --w=boundary_ --h=h --color=0xff | ||
else: | ||
hi_alpha.rectangle 0 (h - boundary_) --w=w --h=boundary_ --color=0xff | ||
Background.draw background_hi_ hi 0 0 w h --autocropped | ||
|
||
canvas.composit hi_alpha hi lo_alpha lo | ||
|
||
set_attribute key/string value -> none: | ||
if key == "value": | ||
value_ = value | ||
recalculate_ | ||
else if key == "min": | ||
min_ = value | ||
recalculate_ | ||
else if key == "max": | ||
max_ = value | ||
recalculate_ | ||
else if key == "background-lo": | ||
background_lo_ = value | ||
invalidate | ||
else if key == "background-hi": | ||
background_hi_ = value | ||
invalidate | ||
else if key == "horizontal": | ||
invalidate | ||
horizontal_ = value | ||
recalculate_ | ||
invalidate | ||
else: | ||
super key value | ||
|
||
value= value/num -> none: | ||
if value != value_: | ||
value_ = value | ||
recalculate_ |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright (C) 2023 Toitware ApS. | ||
// Use of this source code is governed by a Zero-Clause BSD license that can | ||
// be found in the TESTS_LICENSE file. | ||
// Tests some simple vertical sliders where there is a movable boundary between | ||
// two different backgrounds. | ||
import bitmap show * | ||
import expect show * | ||
import font show * | ||
import pixel_display show * | ||
import pixel_display.element show * | ||
import pixel_display.gradient show * | ||
import pixel_display.slider show * | ||
import pixel_display.style show * | ||
import .png_visualizer | ||
|
||
main args: | ||
if args.size != 1: | ||
print "Usage: script.toit png-basename" | ||
exit 1 | ||
WIDTH ::= 220 | ||
HEIGHT ::= 140 | ||
driver := TrueColorPngVisualizer WIDTH HEIGHT args[0] --outline=0x4040ff | ||
display := TrueColorPixelDisplay driver | ||
display.background = 0x808080 | ||
|
||
heat := GradientBackground --angle=0 --specifiers=[ | ||
GradientSpecifier --color=0xc0c000 0, | ||
GradientSpecifier --color=0xff8000 100, | ||
] | ||
|
||
cold := GradientBackground --angle=90 --specifiers=[ | ||
GradientSpecifier --color=0xa0a0a0 0, | ||
GradientSpecifier --color=0x404040 10, | ||
GradientSpecifier --color=0x404040 90, | ||
GradientSpecifier --color=0xa0a0a0 100, | ||
] | ||
|
||
sliders := List 5: | ||
Slider --x=(20 + 40 * it) --y=10 --value=(10 + it * 20) | ||
labels := List 5: | ||
Label --x=(30 + 40 * it) --y=125 --label="$(%c 'A' + it)" --alignment=ALIGN_CENTER | ||
|
||
content := Div --x=0 --y=0 --w=WIDTH --h=HEIGHT --background=0x202020 (sliders + labels) | ||
|
||
display.add content | ||
|
||
sans10 := Font.get "sans10" | ||
|
||
style := Style | ||
--type-map={ | ||
"vertical-slider": Style { | ||
"background-hi": heat, | ||
"background-lo": cold, | ||
"width": 20, | ||
"height": 100, | ||
}, | ||
"label": Style --font=sans10 --color=0xffffff, | ||
} | ||
|
||
content.set_styles [style] | ||
|
||
display.draw | ||
driver.write_png | ||
|
||
sliders[0].value = 50 | ||
sliders[1].value = 70 | ||
sliders[2].value = 10 | ||
sliders[3].value = 90 | ||
sliders[4].value = 30 | ||
|
||
display.draw | ||
driver.write_png |