Created
November 22, 2018 03:28
-
-
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
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
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