Skip to content

Commit ffdf8f1

Browse files
authored
Merge pull request #139 from boydm/improve_error_scene
Improve error scene
2 parents c6c5911 + 45e7ece commit ffdf8f1

File tree

6 files changed

+99
-36
lines changed

6 files changed

+99
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* Buttons, checkboxes, radios, etc can be auto-sized to fix their text
1717
* FontMetrics can be used to measure strings, trim to fit, and more
1818
* Dynamic Textures in the form of raw pixel maps are now supported. This should allow you to capture raw images off of a camera and display them without encoding/decoding
19+
* leading spaces in a text primitive are now rendered
1920

2021
## 0.9.0
2122
* Much improved testing

c_src/texture.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ nif_get_g(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
125125
// get the parameters
126126
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
127127
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
128-
if ( pos < 0 ) {return enif_make_badarg(env);}
129128
if ( pos >= pixels.size ) {return enif_make_badarg(env);}
130129

131130
// return the value of g
@@ -143,7 +142,6 @@ nif_get_ga(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
143142
// get the parameters
144143
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
145144
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
146-
if ( pos < 0 ) {return enif_make_badarg(env);}
147145
if ( pos >= (pixels.size - 1) ) {return enif_make_badarg(env);}
148146

149147
// get the values
@@ -169,7 +167,6 @@ nif_get_rgb(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
169167
// get the parameters
170168
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
171169
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
172-
if ( pos < 0 ) {return enif_make_badarg(env);}
173170
if ( pos >= (pixels.size - 2) ) {return enif_make_badarg(env);}
174171

175172
// get the values
@@ -198,7 +195,6 @@ nif_get_rgba(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
198195
// get the parameters
199196
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
200197
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
201-
if ( pos < 0 ) {return enif_make_badarg(env);}
202198
if ( pos >= (pixels.size - 3) ) {return enif_make_badarg(env);}
203199

204200
// get the values
@@ -227,7 +223,6 @@ nif_put_g(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
227223
// get the parameters
228224
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
229225
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
230-
if ( pos < 0 ) {return enif_make_badarg(env);}
231226
if ( pos >= pixels.size ) {return enif_make_badarg(env);}
232227
if ( !enif_get_uint(env, argv[2], &g) ) {return enif_make_badarg(env);}
233228

@@ -248,7 +243,6 @@ nif_put_ga(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
248243
// get the parameters
249244
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
250245
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
251-
if ( pos < 0 ) {return enif_make_badarg(env);}
252246
if ( pos >= (pixels.size - 1) ) {return enif_make_badarg(env);}
253247
if ( !enif_get_uint(env, argv[2], &g) ) {return enif_make_badarg(env);}
254248
if ( !enif_get_uint(env, argv[3], &a) ) {return enif_make_badarg(env);}
@@ -273,7 +267,6 @@ nif_put_rgb(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
273267
// get the parameters
274268
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
275269
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
276-
if ( pos < 0 ) {return enif_make_badarg(env);}
277270
if ( pos >= (pixels.size - 2) ) {return enif_make_badarg(env);}
278271
if ( !enif_get_uint(env, argv[2], &r) ) {return enif_make_badarg(env);}
279272
if ( !enif_get_uint(env, argv[3], &g) ) {return enif_make_badarg(env);}
@@ -301,7 +294,6 @@ nif_put_rgba(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
301294
// get the parameters
302295
if ( !enif_inspect_binary(env, argv[0], &pixels) ) {return enif_make_badarg(env);}
303296
if ( !enif_get_uint(env, argv[1], &pos) ) {return enif_make_badarg(env);}
304-
if ( pos < 0 ) {return enif_make_badarg(env);}
305297
if ( pos >= (pixels.size - 3) ) {return enif_make_badarg(env);}
306298
if ( !enif_get_uint(env, argv[2], &r) ) {return enif_make_badarg(env);}
307299
if ( !enif_get_uint(env, argv[3], &g) ) {return enif_make_badarg(env);}

lib/scenic/scene.ex

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -634,20 +634,20 @@ defmodule Scenic.Scene do
634634
rescue
635635
err ->
636636
# build error message components
637-
head_msg = "#{inspect(scene_module)} crashed during init"
637+
module_msg = inspect(scene_module)
638638
err_msg = inspect(err)
639-
args_msg = "args: #{inspect(args)}"
639+
args_msg = inspect(args)
640640
stack_msg = Exception.format_stacktrace(__STACKTRACE__)
641641

642642
# assemble into a final message to output to the command line
643643
unless Mix.env() == :test do
644644
[
645645
"\n",
646646
IO.ANSI.red(),
647-
head_msg,
647+
module_msg <> "crashed during init",
648648
"\n",
649649
IO.ANSI.yellow(),
650-
args_msg,
650+
"Scene Args:" <> args_msg,
651651
"\n",
652652
IO.ANSI.red(),
653653
err_msg,
@@ -666,14 +666,14 @@ defmodule Scenic.Scene do
666666
:ok
667667

668668
vp ->
669-
msgs = {head_msg, err_msg, args_msg, stack_msg}
669+
msgs = {module_msg, err_msg, args_msg, stack_msg}
670670
ViewPort.set_root(vp, {Scenic.Scenes.Error, {msgs, scene_module, args}})
671671
end
672672

673673
# purposefully slow down the reply in the event of a crash. Just in
674-
# case it does to into a crazy loop
675-
Process.sleep(400)
676-
{:noreply, nil}
674+
# case it does go into a crazy loop
675+
# Process.sleep(400)
676+
{:noreply, state}
677677
end
678678
end
679679

lib/scenic/scenes/error.ex

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,59 @@ defmodule Scenic.Scenes.Error do
1818
import Scenic.Primitives
1919
import Scenic.Components
2020

21+
# import IEx
22+
2123
@size 20
24+
@margin_h 20
25+
@margin_v 20
26+
@v_spacing @size
27+
28+
@stack_header "Stack Trace\n"
29+
@error_header "Error\n "
30+
@args_header "Scene Args\n "
31+
@mod_header " crashed during init/2"
32+
33+
@font :roboto_mono
34+
@error_color :orange_red
35+
@args_color :yellow
2236

2337
# --------------------------------------------------------
24-
def init({{head_msg, err_msg, args_msg, stack_msg}, scene_mod, scene_args}, opts) do
25-
Graph.build(font: :roboto, font_size: @size)
26-
|> button("Try Again", id: :try_again, translate: {20, 40}, theme: :warning)
27-
|> button("Reset", id: :restart, translate: {136, 40})
28-
|> text(head_msg, translate: {20, 120}, font_size: @size + 4)
29-
|> text(err_msg, translate: {20, 130 + @size}, fill: :red)
30-
|> text(args_msg, translate: {20, 140 + @size * 2}, fill: :yellow)
31-
|> text(stack_msg, translate: {20, 150 + @size * 4}, fill: :red)
38+
def init({{module_msg, err_msg, args_msg, stack_msg}, scene_mod, scene_args}, opts) do
39+
# Get the viewport width
40+
{:ok, %ViewPort.Status{size: {width, _}}} =
41+
opts[:viewport]
42+
|> ViewPort.info()
43+
44+
fm = Scenic.Cache.Static.FontMetrics.get(@font)
45+
wrap_width = width - @margin_h * 2
46+
47+
head_msg = module_msg <> @mod_header
48+
49+
err_msg =
50+
(@error_header <> err_msg)
51+
|> FontMetrics.wrap(wrap_width, @size, fm, indent: 4)
52+
53+
args_msg =
54+
(@args_header <> args_msg)
55+
|> FontMetrics.wrap(wrap_width, @size, fm, indent: 4)
56+
57+
stack_msg =
58+
(@stack_header <> stack_msg)
59+
|> String.replace(" ", " ")
60+
|> FontMetrics.wrap(wrap_width, @size, fm, indent: 4)
61+
62+
head_v = 80
63+
args_v = head_v + msg_height(head_msg, @size) + @v_spacing
64+
err_v = args_v + msg_height(args_msg, @size) + @v_spacing
65+
stack_v = err_v + msg_height(err_msg, @size) + @v_spacing
66+
67+
Graph.build(font: @font, font_size: @size, t: {@margin_h, @margin_v})
68+
|> button("Try Again", id: :try_again, theme: :warning)
69+
|> button("Reset", id: :restart, translate: {116, 0})
70+
|> text(head_msg, translate: {0, head_v}, font_size: @size + 4)
71+
|> text(args_msg, translate: {0, args_v}, fill: @args_color)
72+
|> text(err_msg, translate: {0, err_v}, fill: @error_color)
73+
|> text(stack_msg, translate: {0, stack_v}, fill: @error_color)
3274
|> push_graph()
3375

3476
{:ok, {scene_mod, scene_args, opts[:viewport]}}
@@ -45,4 +87,11 @@ defmodule Scenic.Scenes.Error do
4587
ViewPort.reset(vp)
4688
{:stop, state}
4789
end
90+
91+
defp msg_height(msg, pixel_size) do
92+
msg
93+
|> String.split("\n")
94+
|> Enum.count()
95+
|> Kernel.*(pixel_size)
96+
end
4897
end

lib/utilities/texture.ex

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,18 @@ defmodule Scenic.Utilities.Texture do
148148

149149
# --------------------------------------------------------
150150
def get(texture, x, y)
151-
def get({:g, w, h, p, _}, x, y) when x <= w and y <= h, do: nif_get_g(p, y * w + x)
152-
def get({:ga, w, h, p, _}, x, y) when x <= w and y <= h, do: nif_get_ga(p, y * w + x)
153-
def get({:rgb, w, h, p, _}, x, y) when x <= w and y <= h, do: nif_get_rgb(p, y * w + x)
154-
def get({:rgba, w, h, p, _}, x, y) when x <= w and y <= h, do: nif_get_rgba(p, y * w + x)
151+
152+
def get({:g, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
153+
do: nif_get_g(p, y * w + x)
154+
155+
def get({:ga, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
156+
do: nif_get_ga(p, y * w + x)
157+
158+
def get({:rgb, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
159+
do: nif_get_rgb(p, y * w + x)
160+
161+
def get({:rgba, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
162+
do: nif_get_rgba(p, y * w + x)
155163

156164
defp nif_get_g(_, _), do: :erlang.nif_error("Did not find nif_get_g")
157165
defp nif_get_ga(_, _), do: :erlang.nif_error("Did not find nif_get_ga")
@@ -161,25 +169,25 @@ defmodule Scenic.Utilities.Texture do
161169
# --------------------------------------------------------
162170
def put!(texture, x, y, color)
163171

164-
def put!({:g, w, h, p, hints}, x, y, color) when x <= w and y <= h do
172+
def put!({:g, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
165173
g = prep_color(:g, color)
166174
nif_put(p, y * w + x, g)
167175
{:g, w, h, p, hints}
168176
end
169177

170-
def put!({:ga, w, h, p, hints}, x, y, color) when x <= w and y <= h do
178+
def put!({:ga, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
171179
{g, a} = prep_color(:ga, color)
172180
nif_put(p, y * w + x, g, a)
173181
{:ga, w, h, p, hints}
174182
end
175183

176-
def put!({:rgb, w, h, p, hints}, x, y, color) when x <= w and y <= h do
184+
def put!({:rgb, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
177185
{r, g, b} = prep_color(:rgb, color)
178186
nif_put(p, y * w + x, r, g, b)
179187
{:rgb, w, h, p, hints}
180188
end
181189

182-
def put!({:rgba, w, h, p, hints}, x, y, color) when x <= w and y <= h do
190+
def put!({:rgba, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
183191
{r, g, b, a} = Color.to_rgba(color)
184192
nif_put(p, y * w + x, r, g, b, a)
185193
{:rgba, w, h, p, hints}

test/scenic/scenes/error_test.exs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,27 @@ defmodule Scenic.Scenes.ErrorTest do
99

1010
alias Scenic.Scenes
1111

12+
defmodule FakeViewPort do
13+
use GenServer
14+
15+
def start_link(), do: GenServer.start_link(__MODULE__, nil)
16+
def init(nil), do: {:ok, nil}
17+
18+
def handle_call(:query_info, _, state) do
19+
{:reply, {:ok, %Scenic.ViewPort.Status{size: {500, 400}}}, state}
20+
end
21+
end
22+
1223
test "init" do
13-
self = self()
24+
{:ok, fvp} = FakeViewPort.start_link()
1425

15-
{:ok, {:mod, :args, ^self}} =
26+
{:ok, {:mod, :args, ^fvp}} =
1627
Scenes.Error.init(
17-
{{"head", "err", "args", "stack"}, :mod, :args},
18-
viewport: self
28+
{{"module", "err", "args", "stack"}, :mod, :args},
29+
viewport: fvp
1930
)
31+
32+
Process.exit(fvp, :normal)
2033
end
2134

2235
test "filter_event {:click, :try_again}" do

0 commit comments

Comments
 (0)