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 hidden or 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