Skip to content

Instantly share code, notes, and snippets.

@xinhaoyuan
Created November 22, 2018 03:28
Show Gist options
  • Save xinhaoyuan/6f2c1837151c27f2d00f7d6ae6eaff20 to your computer and use it in GitHub Desktop.
Save xinhaoyuan/6f2c1837151c27f2d00f7d6ae6eaff20 to your computer and use it in GitHub Desktop.
Adding sort of horizontal scrolling and zooming support in et_viewer. Diffed from otp-22-dev
diff --git a/lib/et/src/et_wx_contents_viewer.erl b/lib/et/src/et_wx_contents_viewer.erl
index 580c921139..0bc70ce22a 100644
--- a/lib/et/src/et_wx_contents_viewer.erl
+++ b/lib/et/src/et_wx_contents_viewer.erl
@@ -47,9 +47,10 @@
filters, % List of possible filters
win, % GUI: Frame object
frame, % GUI: Frame object
- panel, % GUI: Panel object
- width, % GUI: Window width
+ width,
height,
+ panel, % GUI: Panel object
+ font,
editor,
menu_data, % GUI: Window height
wx_debug, % GUI: WX debug level
@@ -107,7 +108,7 @@ default_state() ->
filters = [?DEFAULT_FILTER],
width = 600,
height = 300,
- wx_debug = 0,
+ wx_debug = 0,
trap_exit = true}.
parse_opt([], S) ->
@@ -464,8 +465,10 @@ create_window(S) ->
_ = wxTextCtrl:setDefaultStyle(Editor, TextAttr),
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
_ = wxSizer:add(Sizer, Editor, [{flag, ?wxEXPAND}, {proportion, 1}]),
- FilteredEvent = config_editor(Editor, S),
- S2 = S#state{win = Frame, panel = Panel, filtered_event = FilteredEvent},
+ S1 = S#state{win = Frame, panel = Panel, font = Font},
+ FilteredEvent = config_editor(Editor, S1),
+ {NewW, NewH} = wxWindow:getSize(Frame),
+ S2 = S1#state{filtered_event = FilteredEvent, width = NewW, height = NewH},
HideData = create_hide_menu(Bar, S2),
SearchData = create_search_menu(Bar, S2),
FilterData = create_filter_menu(Bar, S#state.filters),
@@ -586,19 +589,26 @@ config_editor(Editor, S) ->
FilterFun = F#filter.function,
case catch FilterFun(Event) of
true ->
- do_config_editor(Editor, Event, lightblue, S#state.event_order);
+ do_config_editor(Editor, Event, lightblue, S#state.event_order, S);
{true, Event2} when is_record(Event2, event) ->
- do_config_editor(Editor, Event2, lightblue, S#state.event_order);
+ do_config_editor(Editor, Event2, lightblue, S#state.event_order, S);
false ->
- do_config_editor(Editor, Event, red, S#state.event_order);
+ do_config_editor(Editor, Event, red, S#state.event_order, S);
Bad ->
Contents = {bad_filter, Name, Bad},
BadEvent = Event#event{contents = Contents},
- do_config_editor(Editor, BadEvent, red, S#state.event_order)
+ do_config_editor(Editor, BadEvent, red, S#state.event_order, S)
end.
-do_config_editor(Editor, Event, _Colour, TsKey) ->
+do_config_editor(Editor, Event, _Colour, TsKey, S) ->
String = event_to_string(Event, TsKey),
+ %% Auto-fit the window size to the content
+ Ext = wxWindow:getTextExtent(Editor, String, [{theFont, S#state.font}]),
+ {W, H, _, _} = Ext,
+ %% Add a little space to prevent the scrollbar. Could do this more smartly?
+ wxWindow:setSize(Editor, W + 20, H + 20),
+ wxWindow:fit(S#state.panel),
+ wxWindow:fit(S#state.win),
wxTextCtrl:appendText(Editor, String),
Event.
diff --git a/lib/et/src/et_wx_viewer.erl b/lib/et/src/et_wx_viewer.erl
index 4dd44e7a4c..a84dd7cf21 100644
--- a/lib/et/src/et_wx_viewer.erl
+++ b/lib/et/src/et_wx_viewer.erl
@@ -38,7 +38,6 @@
-define(unknown, "UNKNOWN").
-define(initial_x, 10).
--define(incr_x, 60).
-define(initial_y, 15).
-define(incr_y, 15).
@@ -59,6 +58,9 @@
n_events, % Number of events available in the collector
max_actors, % Maximum number of shown actors
actors, % List of known actors
+ vis_actors, % Current visible actors
+ actors_offset, % the first actor to draw
+ actors_per_page, % Maximum number of shown actors
refresh_needed, % Refresh is needed in order to show all actors
detail_level, % Show only events with lesser detail level
hide_actions, % Hide/show events where to == from actor (bool)
@@ -74,6 +76,7 @@
scale, % GUI: Scaling factor on canvas
normal_font, % GUI: Font to be used on text labels
bold_font, % GUI: Font to be used on text labels
+ actor_width,
pen,
brush,
print_psdd,
@@ -146,11 +149,15 @@ default_state() ->
events = queue_new(),
max_actors = 5,
actors = [create_actor(?unknown)],
+ vis_actors = [create_actor(?unknown)],
+ actors_offset = 0,
+ actors_per_page = 100,
pending_actor = ?unknown,
hide_actions = false,
hide_actors = false,
display_all = true,
context = display,
+ actor_width = 80,
refresh_needed = false,
scale = 2,
canvas_height = 0,
@@ -327,8 +334,9 @@ init([S]) when is_record(S, state) ->
?MODULE),
S2 = create_main_window(S),
EventsPerPage = events_per_page(S2, S2#state.height),
- S3 = revert_main_window(S2#state{events_per_page = EventsPerPage}),
- Timeout = timeout(S3),
+ ActorsPerPage = actors_per_page(S2, S2#state.width),
+ S3 = revert_main_window(S2#state{events_per_page = EventsPerPage, actors_per_page = ActorsPerPage}),
+ Timeout = timeout(S3),
{ok, S3, Timeout}.
%%----------------------------------------------------------------------
@@ -625,7 +633,7 @@ handle_info(#wx{event = #wxMouse{type = left_down, x = X, y = Y}}, S) ->
S;
Actors ->
N = x_to_n(X, S),
- A = lists:nth(N, Actors),
+ A = lists:nth(N + S#state.actors_offset, Actors),
S#state{pending_actor = A}
end;
{event, N} ->
@@ -646,7 +654,7 @@ handle_info(#wx{event = #wxMouse{type = left_up, x = X, y = Y}}, S) ->
S;
Actors ->
N = x_to_n(X, S),
- A = lists:nth(N, Actors),
+ A = lists:nth(N + S#state.actors_offset, Actors),
Pending = S#state.pending_actor,
if
A#actor.name =:= Pending#actor.name ->
@@ -678,7 +686,7 @@ handle_info(#wx{event = #wxMouse{type = right_up, x = X, y = Y}}, S) ->
Actors ->
%% Toggle exclude actor
N = x_to_n(X, S),
- A = lists:nth(N, Actors),
+ A = lists:nth(N + S#state.actors_offset, Actors),
A2 = A#actor{exclude = not A#actor.exclude},
Actors2 = lists:keyreplace(A#actor.name, #actor.name, Actors, A2),
S2 = S#state{actors = Actors2},
@@ -713,6 +721,22 @@ handle_info(#wx{event = #wxKey{keyCode = KeyCode, shiftDown = SD}}, S) ->
?WXK_PAGEDOWN ->
S2 = scroll_next(S),
noreply(S2);
+ $W ->
+ S2 = S#state{actor_width = S#state.actor_width + 80},
+ S3 = S2#state{actors_per_page = actors_per_page(S2, S2#state.width)},
+ noreply(refresh_main_window(S3));
+ $S when S#state.actor_width > 80 ->
+ S2 = S#state{actor_width = S#state.actor_width - 80},
+ S3 = S2#state{actors_per_page = actors_per_page(S2, S2#state.width)},
+ noreply(refresh_main_window(S3));
+ ?WXK_LEFT ->
+ NewOffset = lists:max([0, S#state.actors_offset - 1]),
+ S2 = S#state{actors_offset = NewOffset},
+ noreply(refresh_main_window(S2));
+ ?WXK_RIGHT ->
+ NewOffset = lists:min([length(S#state.actors) - 1, S#state.actors_offset + 1]),
+ S2 = S#state{actors_offset = NewOffset},
+ noreply(refresh_main_window(S2));
$F when SD =:= true ->
et_collector:multicast(S#state.collector_pid, first),
noreply(S);
@@ -825,27 +849,34 @@ handle_info(#wx{event = #wxSize{size = {OldW, OldH}}} = Wx, S) ->
#wx{event = #wxSize{type = size, size = {W, H}}} = get_latest_resize(Wx),
S2 = S#state{width = W, height = H, canvas_width = W, canvas_height = H},
EventsPerPage = events_per_page(S, H),
- Diff = EventsPerPage - S#state.events_per_page,
- S6 =
+ DiffE = EventsPerPage - S#state.events_per_page,
+ ActorsPerPage = actors_per_page(S, W),
+ DiffA = ActorsPerPage - S#state.actors_per_page,
+ {ToRefresh, S3} =
if
- OldW =:= W, OldH =:= H, S2#state.events_per_page =:= EventsPerPage ->
- S2;
- Diff =:= 0 ->
- refresh_main_window(S2);
- Diff > 0 ->
- OldEvents = queue_to_list(S2#state.events),
- {S3, NewEvents} = collect_more_events(S2, S2#state.last_event, Diff),
- S4 = S3#state{events_per_page = EventsPerPage},
- S5 = replace_events(S4, OldEvents ++ NewEvents),
- refresh_main_window(S5);
- Diff < 0 ->
- OldEvents = queue_to_list(S2#state.events),
- RevEvents = delete_n(lists:reverse(OldEvents), abs(Diff)),
- S3 = S2#state{events_per_page = EventsPerPage},
- S4 = replace_events(S3, lists:reverse(RevEvents)),
- refresh_main_window(S4)
+ OldW =:= W, OldH =:= H, DiffE =:= 0, DiffA =:= 0 ->
+ {false, S2};
+ DiffE =:= 0 ->
+ {true, S2#state{actors_per_page = ActorsPerPage}};
+ DiffE > 0 ->
+ OldEvents = queue_to_list(S2#state.events),
+ {_S3, NewEvents} = collect_more_events(S2, S2#state.last_event, DiffE),
+ _S4 = _S3#state{events_per_page = EventsPerPage, actors_per_page = ActorsPerPage},
+ _S5 = replace_events(_S4, OldEvents ++ NewEvents),
+ {true, _S5};
+ DiffE < 0 ->
+ OldEvents = queue_to_list(S2#state.events),
+ RevEvents = delete_n(lists:reverse(OldEvents), abs(DiffE)),
+ _S3 = S2#state{events_per_page = EventsPerPage, actors_per_page = ActorsPerPage},
+ _S4 = replace_events(_S3, lists:reverse(RevEvents)),
+ {true, _S4}
end,
- noreply(S6);
+ case ToRefresh of
+ true ->
+ noreply(refresh_main_window(S3));
+ false ->
+ noreply(S3)
+ end;
handle_info(#wx{event = #wxMouse{type = enter_window}}, S) ->
wxWindow:setFocus(S#state.canvas), % Get keyboard focus
noreply(S);
@@ -1640,84 +1671,86 @@ draw_label(Label, FromName, ToName, FromPos, ToPos, S, DC) ->
draw_all_actors(S, DC) ->
Scale = S#state.scale,
- Fun = fun(A, X) ->
- case draw_actor(A, X, S, DC) of
- true ->
- X + (?incr_x * Scale);
- false ->
- X
- end
+ NewVisActors = lists:filter(fun (A) -> to_draw_actor(A, S) end, S#state.actors),
+ NewOffset = lists:max([0, lists:min([length(NewVisActors) - S#state.actors_per_page, S#state.actors_offset])]),
+ Fun = fun(A, {C, X}) ->
+ if
+ %% also draw the first out-of-bound actor
+ NewOffset =< C, C =< NewOffset + S#state.actors_per_page ->
+ draw_actor(A, X, S, DC),
+ {C + 1, X + (S#state.actor_width * Scale)};
+ true ->
+ {C + 1, X}
+ end
end,
- lists:foldl(Fun, ?initial_x * Scale, S#state.actors),
- S.
+ lists:foldl(Fun, {0, ?initial_x * Scale}, NewVisActors),
+ S#state{actors_offset = NewOffset, vis_actors = NewVisActors, y_pos = S#state.y_pos}.
-%% Returns: {NeedsRefreshBool, {ActorPos, NewsS, NewActors}}
+%% Returns: {NeedsRefreshBool, {Name, Pos, NewState}}
ensure_actor(Name, S, DC) ->
do_ensure_actor(Name, S, S#state.actors, 0, DC).
do_ensure_actor(Name, S, [H | _], N, _DC) when H#actor.name =:= Name ->
- Pos = (?initial_x + (N * ?incr_x)) * S#state.scale,
+ Pos = (?initial_x + ((N - S#state.actors_offset) * S#state.actor_width)) * S#state.scale,
{false, {Name, Pos, S}};
do_ensure_actor(Name, S, [H | T], N, DC) ->
- if
- S#state.hide_actors, H#actor.exclude ->
- do_ensure_actor(Name, S, T, N, DC);
- true ->
- do_ensure_actor(Name, S, T, N + 1, DC)
+ case to_draw_actor(H, S) of
+ true ->
+ do_ensure_actor(Name, S, T, N + 1, DC);
+ false ->
+ do_ensure_actor(Name, S, T, N, DC)
end;
do_ensure_actor(Name, S, [], N, DC) ->
%% A brand new actor, let's see if it does fit
- Pos = (?initial_x + (N * ?incr_x)) * S#state.scale,
+ Pos = (?initial_x + ((N - S#state.actors_offset) * S#state.actor_width)) * S#state.scale,
MaxActors = S#state.max_actors,
if
is_integer(MaxActors), N > MaxActors ->
%% Failed on max_actors limit, put into unknown
%% Assume that unknown always is in actor list
ensure_actor(?unknown, S, DC);
- Pos > (S#state.canvas_width - ((?initial_x - 15) * S#state.scale)) ->
+ Pos < 0; Pos > (S#state.canvas_width - ((?initial_x - 15) * S#state.scale)) ->
%% New actor does not fit in canvas, refresh needed
A = create_actor(Name),
draw_actor(A, Pos, S, DC),
- {true, {Name, Pos, S#state{actors = S#state.actors ++ [A]}}};
+ {true, {Name, Pos, S#state{actors = S#state.actors ++ [A], vis_actors = S#state.vis_actors ++ [A]}}};
true ->
%% New actor fits in canvas. Draw the new actor.
A = create_actor(Name),
draw_actor(A, Pos, S, DC),
- {false, {Name, Pos, S#state{actors = S#state.actors ++ [A]}}}
+ {false, {Name, Pos, S#state{actors = S#state.actors ++ [A], vis_actors = S#state.vis_actors ++ [A]}}}
end.
+to_draw_actor(A, S) when S#state.hide_actors, A#actor.exclude -> false;
+to_draw_actor(_, _) -> true.
+
draw_actor(A, LineX, S, DC) ->
- if
- S#state.hide_actors, A#actor.exclude ->
- false;
- true ->
- Scale = S#state.scale,
- TextX = LineX - (5 * Scale),
- {TextY, LineTopY, LineBotY} = calc_y(S),
- Color =
- case A#actor.name of
- ?unknown -> {255,126,0};% orange
- _ -> {227,38,54} % red
- end,
- {String, Font} =
- if
- S#state.context =:= display, A#actor.exclude ->
- {"(" ++ A#actor.string ++ ")", S#state.normal_font};
- S#state.context =:= display, A#actor.include ->
- {"[" ++ A#actor.string ++ "]", S#state.bold_font};
- true ->
- {A#actor.string, S#state.normal_font}
- end,
- write_text(String, TextX, TextY, Color, Font, S, DC),
- wxPen:setColour(S#state.pen, Color),
- wxDC:setPen(DC, S#state.pen),
- wxDC:drawLines(DC, [{LineX, LineTopY}, {LineX, LineBotY}]),
- true
- end.
+ Scale = S#state.scale,
+ TextX = LineX - (5 * Scale),
+ {TextY, LineTopY, LineBotY} = calc_y(S),
+ Color =
+ case A#actor.name of
+ ?unknown -> {255,126,0};% orange
+ _ -> {227,38,54} % red
+ end,
+ {String, Font} =
+ if
+ S#state.context =:= display, A#actor.exclude ->
+ {"(" ++ A#actor.string ++ ")", S#state.normal_font};
+ S#state.context =:= display, A#actor.include ->
+ {"[" ++ A#actor.string ++ "]", S#state.bold_font};
+ true ->
+ {A#actor.string, S#state.normal_font}
+ end,
+ write_text(String, TextX, TextY, Color, Font, S, DC),
+ wxPen:setColour(S#state.pen, Color),
+ wxDC:setPen(DC, S#state.pen),
+ wxDC:drawLines(DC, [{LineX, LineTopY}, {LineX, LineBotY}]),
+ ok.
calc_y(#state{canvas_height = Height, scale = Scale}) ->
TextY = ?initial_y * Scale,
- LineTopY = round(TextY + ((?incr_y / 2) * Scale)),
+ LineTopY = round(TextY + (?incr_y * 0.5) * Scale),
LineBotY = Height,
%% LineBotY = round(Height - ((?incr_y / 2) * Scale)),
{TextY, LineTopY, LineBotY}.
@@ -1821,7 +1854,7 @@ x_to_n(X, S) ->
Scale = S#state.scale,
Len = length(S#state.actors),
X2 = X - (?initial_x * Scale),
- N = X2 / (?incr_x * Scale),
+ N = X2 / (S#state.actor_width * Scale),
N2 = trunc(N + 1.5),
if
N2 > Len -> Len;
@@ -2031,7 +2064,10 @@ update_scroll_bar(#state{scroll_bar = ScrollBar,
events_per_page(S, PageHeight) ->
EventsPerPage = ((PageHeight - (?initial_y * S#state.scale)) div (?incr_y * S#state.scale)),
- lists:max([1, EventsPerPage]).
+ lists:max([1, EventsPerPage]).
+
+actors_per_page(S, PageWidth) ->
+ lists:max([1, (PageWidth - (?initial_x * S#state.scale)) div (S#state.actor_width * S#state.scale)]).
select_file(Frame, Message, DefaultFile, Style) ->
Dialog = wxFileDialog:new(Frame,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment