diff options
Diffstat (limited to 'lib/debugger/src/dbg_ui_trace_win.erl')
-rw-r--r-- | lib/debugger/src/dbg_ui_trace_win.erl | 1595 |
1 files changed, 0 insertions, 1595 deletions
diff --git a/lib/debugger/src/dbg_ui_trace_win.erl b/lib/debugger/src/dbg_ui_trace_win.erl deleted file mode 100644 index beb3fbd71e..0000000000 --- a/lib/debugger/src/dbg_ui_trace_win.erl +++ /dev/null @@ -1,1595 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2012. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(dbg_ui_trace_win). --compile([{nowarn_deprecated_function,{gs,button,2}}, - {nowarn_deprecated_function,{gs,button,3}}, - {nowarn_deprecated_function,{gs,checkbutton,2}}, - {nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,create,4}}, - {nowarn_deprecated_function,{gs,destroy,1}}, - {nowarn_deprecated_function,{gs,editor,2}}, - {nowarn_deprecated_function,{gs,editor,3}}, - {nowarn_deprecated_function,{gs,entry,2}}, - {nowarn_deprecated_function,{gs,entry,3}}, - {nowarn_deprecated_function,{gs,frame,3}}, - {nowarn_deprecated_function,{gs,grid,3}}, - {nowarn_deprecated_function,{gs,gridline,2}}, - {nowarn_deprecated_function,{gs,label,2}}, - {nowarn_deprecated_function,{gs,label,3}}, - {nowarn_deprecated_function,{gs,menubar,2}}, - {nowarn_deprecated_function,{gs,read,2}}, - {nowarn_deprecated_function,{gs,window,2}}, - {nowarn_deprecated_function,{gs,window,3}}]). - -%% External exports --export([init/0]). --export([create_win/4, get_window/1, - configure/2, - enable/2, is_enabled/1, select/2, - add_break/3, update_break/2, delete_break/2, - clear_breaks/1, clear_breaks/2, - display/1, % Help messages - is_shown/2, % Code area - show_code/3, show_no_code/1, remove_code/2, - mark_line/3, unmark_line/1, - select_line/2, selected_line/1, - eval_output/2, % Evaluator area - update_bindings/1, % Bindings area - trace_output/1, % Trace area - handle_event/2 - ]). --export([helpwin/4, % Help windows - helpwin/5]). - --record(breakInfo, {point, status, break}). --record(winInfo, {window, % gsobj() - size, % {W, H} - flags, % {F,F,F,F} F = open|close - - marked_line=0, % integer() Current line - selected_line=0, % integer() Selected line - - breaks=[], % [#breakInfo{}] Known breakpoints - - editor, % {Mod, Editor} Visible code editor - editors=[] % [{Mod,Editor}] Code editors - }). - - -%%==================================================================== -%% External exports -%%==================================================================== - -%%-------------------------------------------------------------------- -%% init() -> GS -%% GS = term() -%%-------------------------------------------------------------------- -init() -> - dbg_ui_win:init(). - -%%-------------------------------------------------------------------- -%% create_win(GS, Title, TraceWin, Menus) -> #winInfo{} -%% GS = gsobj() -%% Title = string() -%% TraceWin = [WinArea] -%% WinArea = 'Button|Evaluator|Bindings|Trace Area' -%% Menus = [menu()] See dbg_ui_win.erl -%%-------------------------------------------------------------------- -create_win(GS, Title, TraceWin, Menus) -> - Bu = flip(lists:member('Button Area', TraceWin)), - Ev = flip(lists:member('Evaluator Area', TraceWin)), - Bi = flip(lists:member('Bindings Area', TraceWin)), - Tr = flip(lists:member('Trace Area', TraceWin)), - - Win = gs:window(trace_window, GS, [{title, Title}, - {width, 550}, - {configure,true}, {destroy,true}, - {keypress,true}, {motion,true}]), - - MenuBar = gs:menubar(Win, []), - dbg_ui_win:create_menus(MenuBar, Menus), - dbg_ui_winman:windows_menu(MenuBar), - - FrameOpts = [{anchor,nw}, {relief,raised}, {bw,2}, {keypress,true}], - Editor = code_area(2, 25, FrameOpts, Win), - button_area(Bu, 2, 235, FrameOpts, Win), - eval_area({Ev,Bi}, 2, 265, FrameOpts, Win), - bind_area({Ev,Bi}, 300, 265, FrameOpts, Win), - trace_area(Tr, 2, 475, FrameOpts, Win), - - Flags = {Bu, Ev, Bi, Tr}, - resizebar(rb1(Flags), 'RB1', 2, 225, 710, 10, Win), - resizebar(rb2(Flags), 'RB2', 2, 465, 710, 10, Win), - resizebar(rb3(Flags), 'RB3', 290, 265, 10, 200, Win), - config_v(), - config_h(), - - gs:config(Win,{height, - 25 + - gs:read('CodeArea', height) + - gs:read('RB1', height) + - gs:read('ButtonArea', height) + - erlang:max(gs:read('EvalArea', height), - gs:read('BindArea', height)) + - gs:read('RB2', height) + - gs:read('TraceArea', height)}), - - gs:config(Win, {map, true}), - #winInfo{window=Win, size={gs:read(Win,width), gs:read(Win,height)}, - flags=Flags, - editor={'$top', Editor}, editors=[{'$top', Editor}]}. - -flip(true) -> open; -flip(false) -> close. - -%%-------------------------------------------------------------------- -%% get_window(WinInfo) -> Window -%% WinInfo = #winInfo{} -%% Window = gsobj() -%%-------------------------------------------------------------------- -get_window(WinInfo) -> - WinInfo#winInfo.window. - -%%-------------------------------------------------------------------- -%% configure(WinInfo, TraceWin) -> WinInfo -%% WinInfo = #winInfo{} -%% TraceWin = [WinArea] -%% WinArea = 'Button|Evaluator|Bindings|Trace Area' -%% Window areas should be opened or closed. -%%-------------------------------------------------------------------- -configure(WinInfo, TraceWin) -> - {Bu1, Ev1, Bi1, Tr1} = OldFlags = WinInfo#winInfo.flags, - Bu2 = flip(lists:member('Button Area', TraceWin)), - Ev2 = flip(lists:member('Evaluator Area', TraceWin)), - Bi2 = flip(lists:member('Bindings Area', TraceWin)), - Tr2 = flip(lists:member('Trace Area', TraceWin)), - NewFlags = {Bu2, Ev2, Bi2, Tr2}, - - Win = WinInfo#winInfo.window, - W = gs:read(Win, width), - H = gs:read(Win, height), - - H2 = if - Bu1 =:= close, Bu2 =:= open -> - resize_button_area(open, width, W-4), - gs:config('ButtonArea', {height, 30}), - H+30; - Bu1 =:= open, Bu2 =:= close -> - gs:config('ButtonArea', [{width, 0}, {height, 0}]), - H-30; - true -> H - end, - H3 = if - Ev1 =:= close, Ev2 =:= open, Bi1 =:= open -> - Wnew1 = round((W-10-4)/2), % W = window/2 - rb - pads - Hbi1 = gs:read('BindArea', height), % H = bind area h - resize_eval_area(open, width, Wnew1), - resize_eval_area(open, height, Hbi1), - gs:config('RB3', {width, 10}), - gs:config('RB3', {height, Hbi1}), - resize_bind_area(open, width, - Wnew1-gs:read('BindArea', width)), - H2; - Ev1 =:= close, Ev2 =:= open, Bi1 =:= close -> - resize_eval_area(open, width, W-4), - resize_eval_area(open, height, 200), - H2+200; - Ev1 =:= open, Ev2 =:= close, Bi1 =:= open -> - gs:config('EvalArea', [{width,0}, {height,0}]), - gs:config('RB3', [{width, 0}, {height, 0}]), - Wnew2 = W-4, - resize_bind_area(open, width, - Wnew2-gs:read('BindArea', width)), - H2; - Ev1 =:= open, Ev2 =:= close, Bi1 =:= close -> - Hs1 = gs:read('EvalArea', height), - gs:config('EvalArea', [{width, 0}, {height, 0}]), - H2-Hs1; - true -> H2 - end, - H4 = if - Bi1 =:= close, Bi2 =:= open, Ev2 =:= open -> - Wnew3 = round((W-10-4)/2), % W = window/2 - rb - pads - Hs2 = gs:read('EvalArea', height), % H = eval area h - resize_bind_area(open, width, Wnew3), - resize_bind_area(open, height, Hs2), - gs:config('RB3', [{width,10},{height,Hs2}]), - resize_eval_area(open, width, - Wnew3-gs:read('EvalArea', width)), - H3; - Bi1 =:= close, Bi2 =:= open, Ev2 =:= close -> - resize_bind_area(open, width, W-4), - resize_bind_area(open, height, 200), - H3+200; - Bi1 =:= open, Bi2 =:= close, Ev2 =:= open -> - gs:config('BindArea', [{width, 0}, {height, 0}]), - gs:config('RB3', [{width, 0}, {height, 0}]), - Wnew4 = W-4, - resize_eval_area(open, width, - Wnew4-gs:read('EvalArea', width)), - H3; - Bi1 =:= open, Bi2 =:= close, Ev2 =:= close -> - Hbi2 = gs:read('BindArea', height), - gs:config('BindArea', [{width, 0}, {height, 0}]), - H3-Hbi2; - true -> H3 - end, - H5 = if - Tr1 =:= close, Tr2 =:= open -> - resize_trace_area(open, width, W-4), - resize_trace_area(open, height, 200), - H4+200; - Tr1 =:= open, Tr2 =:= close -> - Hf = gs:read('TraceArea', height), - gs:config('TraceArea', [{width, 0}, {height, 0}]), - H4-Hf; - true -> H4 - end, - gs:config(Win, {height, H5}), - - RB1old = rb1(OldFlags), RB1new = rb1(NewFlags), - if - RB1old =:= close, RB1new =:= open -> - gs:config('RB1', [{width, W-4}, {height, 10}]), - gs:config(Win, {height, gs:read(Win, height)+10}); - RB1old =:= open, RB1new =:= close -> - gs:config('RB1', [{width, 0}, {height, 0}, lower]), - gs:config(Win, {height, gs:read(Win, height)-10}); - true -> ignore - end, - - RB2old = rb2(OldFlags), RB2new = rb2(NewFlags), - if - RB2old =:= close, RB2new =:= open -> - gs:config('RB2', [{width, W-4}, {height, 10}]), - gs:config(Win, {height,gs:read(Win, height)+10}); - RB2old =:= open, RB2new =:= close -> - gs:config('RB2', [{width, 0}, {height, 0}, lower]), - gs:config(Win, {height, gs:read(Win, height)-10}); - true -> ignore - end, - config_v(), - config_h(), - - flush_configure(), - - WinInfo#winInfo{size={gs:read(Win, width), gs:read(Win, height)}, - flags=NewFlags}. - -flush_configure() -> - receive - {gs, _Id, configure, _Data, _Arg} -> - flush_configure() - after 100 -> - true - end. - -%%-------------------------------------------------------------------- -%% enable([MenuItem], Bool) -%% is_enabled(MenuItem) -> Bool -%% MenuItem = atom() -%% Bool = boolean() -%%-------------------------------------------------------------------- -enable(MenuItems, Bool) -> - lists:foreach(fun(MenuItem) -> - gs:config(MenuItem, {enable, Bool}), - case is_button(MenuItem) of - {true, Button} -> - gs:config(Button, {enable, Bool}); - false -> ignore - end - end, - MenuItems). - -is_enabled(MenuItem) -> - gs:read(MenuItem, enable). - -%%-------------------------------------------------------------------- -%% select(MenuItem, Bool) -%% MenuItem = atom() -%% Bool = boolean() -%%-------------------------------------------------------------------- -select(MenuItem, Bool) -> - dbg_ui_win:select(MenuItem, Bool). - -%%-------------------------------------------------------------------- -%% add_break(WinInfo, Name, {Point, Options}) -> WinInfo -%% WinInfo = #winInfo{} -%% Name = atom() Menu name -%% Point = {Mod, Line} -%% Options = [Status, Action, Mods, Cond] -%% Status = active | inactive -%% Action = enable | disable | delete -%% Mods = null (not used) -%% Cond = null | {Mod, Func} -%%-------------------------------------------------------------------- -add_break(WinInfo, Menu, {{Mod,Line},[Status|_Options]}=Break) -> - case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of - {Mod, Editor} -> - add_break_to_code(Editor, Line, Status); - false -> ignore - end, - add_break_to_menu(WinInfo, Menu, Break). - -add_break_to_code(Editor, Line, Status) -> - Color = if Status =:= active -> red; Status =:= inactive -> blue end, - config_editor(Editor, [{overwrite,{{Line,0},"-@- "}}, - {fg,{{{Line,0},{Line,lineend}}, Color}}]). - -add_break_to_menu(WinInfo, Menu, {Point, [Status|_Options]=Options}) -> - Break = dbg_ui_win:add_break(Menu, Point), - dbg_ui_win:update_break(Break, Options), - BreakInfo = #breakInfo{point=Point, status=Status, break=Break}, - WinInfo#winInfo{breaks=[BreakInfo|WinInfo#winInfo.breaks]}. - -%%-------------------------------------------------------------------- -%% update_break(WinInfo, {Point, Options}) -> WinInfo -%% WinInfo = #winInfo{} -%% Point = {Mod, Line} -%% Options = [Status, Action, Mods, Cond] -%% Status = active | inactive -%% Action = enable | disable | delete -%% Mods = null (not used) -%% Cond = null | {Mod, Func} -%%-------------------------------------------------------------------- -update_break(WinInfo, {{Mod,Line},[Status|_Options]}=Break) -> - case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of - {Mod, Editor} -> - add_break_to_code(Editor, Line, Status); - false -> ignore - end, - update_break_in_menu(WinInfo, Break). - -update_break_in_menu(WinInfo, {Point, [Status|_Options]=Options}) -> - {value, BreakInfo} = lists:keysearch(Point, #breakInfo.point, - WinInfo#winInfo.breaks), - dbg_ui_win:update_break(BreakInfo#breakInfo.break, Options), - BreakInfo2 = BreakInfo#breakInfo{status=Status}, - WinInfo#winInfo{breaks=lists:keyreplace(Point, #breakInfo.point, - WinInfo#winInfo.breaks, - BreakInfo2)}. - -%%-------------------------------------------------------------------- -%% delete_break(WinInfo, Point) -> WinInfo -%% WinInfo = #winInfo{} -%% Point = {Mod, Line} -%%-------------------------------------------------------------------- -delete_break(WinInfo, {Mod,Line}=Point) -> - case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of - {Mod, Editor} -> delete_break_from_code(Editor, Line); - false -> ignore - end, - delete_break_from_menu(WinInfo, Point). - -delete_break_from_code(Editor, Line) -> - Prefix = string:substr(integer_to_list(Line)++": ", 1, 5), - config_editor(Editor, [{overwrite,{{Line,0},Prefix}}, - {fg,{{{Line,0},{Line,lineend}}, black}}]). - -delete_break_from_menu(WinInfo, Point) -> - {value, BreakInfo} = lists:keysearch(Point, #breakInfo.point, - WinInfo#winInfo.breaks), - dbg_ui_win:delete_break(BreakInfo#breakInfo.break), - WinInfo#winInfo{breaks=lists:keydelete(Point, #breakInfo.point, - WinInfo#winInfo.breaks)}. - -%%-------------------------------------------------------------------- -%% clear_breaks(WinInfo) -> WinInfo -%% clear_breaks(WinInfo, Mod) -> WinInfo -%% WinInfo = #winInfo{} -%%-------------------------------------------------------------------- -clear_breaks(WinInfo) -> - clear_breaks(WinInfo, all). -clear_breaks(WinInfo, Mod) -> - Remove = if - Mod =:= all -> WinInfo#winInfo.breaks; - true -> - lists:filter(fun(#breakInfo{point={Mod2,_L}}) -> - if - Mod2 =:= Mod -> true; - true -> false - end - end, - WinInfo#winInfo.breaks) - end, - lists:foreach(fun(#breakInfo{point=Point}) -> - delete_break(WinInfo, Point) - end, - Remove), - Remain = WinInfo#winInfo.breaks -- Remove, - WinInfo#winInfo{breaks=Remain}. - -%%-------------------------------------------------------------------- -%% display(Arg) -%% Arg = idle | {Status,Mod,Line} | {running,Mod} -%% | {exit,Where,Reason} | {text,Text} -%% Status = break | wait | Level -%% Level = int() -%% Mod = atom() -%% Line = integer() -%% Where = {Mod,Line} | null -%% Reason = term() -%% Text = string() -%%-------------------------------------------------------------------- -display(Arg) -> - Str = case Arg of - idle -> "State: uninterpreted"; - {exit, {Mod,Line}, Reason} -> - gs:config(trace_window, raise), - io_lib:format("State: EXITED [~w.erl/~w], Reason:~w", - [Mod, Line, Reason]); - {exit, null, Reason} -> - gs:config(trace_window, raise), - io_lib:format("State: EXITED [uninterpreted], " - "Reason:~w", [Reason]); - {Level, null, _Line} when is_integer(Level) -> - io_lib:format("*** Call level #~w " - "(in non-interpreted code)", - [Level]); - {Level, Mod, Line} when is_integer(Level) -> - io_lib:format("*** Call level #~w [~w.erl/~w]", - [Level, Mod, Line]); - {Status, Mod, Line} -> - What = case Status of - wait -> 'receive'; - _ -> Status - end, - io_lib:format("State: ~w [~w.erl/~w]", - [What, Mod, Line]); - {running, Mod} -> - io_lib:format("State: running [~w.erl]", [Mod]); - {text, Text} -> Text - end, - gs:config(info_window, {label,{text,lists:flatten(Str)}}). - -%%-------------------------------------------------------------------- -%% is_shown(WinInfo, Mod) -> {true, WinInfo} | false -%% show_code(WinInfo, Mod, Contents) -> WinInfo -%% show_no_code(WinInfo) -> WinInfo -%% remove_code(WinInfo, Mod) -> WinInfo -%% WinInfo = #winInfo{} -%% Mod = atom() -%% Contents = string() -%% Note: remove_code/2 should not be used for currently shown module. -%%-------------------------------------------------------------------- -is_shown(WinInfo, Mod) -> - case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of - {Mod, Editor} -> - gs:config(Editor, raise), - {true, WinInfo#winInfo{editor={Mod, Editor}}}; - false -> false - end. - -show_code(WinInfo, Mod, Contents) -> - Editors = WinInfo#winInfo.editors, - {Flag, Editor} = case lists:keyfind(Mod, 1, Editors) of - {Mod, Ed} -> {existing, Ed}; - false -> {new, code_editor()} - end, - %% Insert code and update breakpoints, if any - config_editor(Editor, [raise, clear]), - show_code(Editor, Contents), - lists:foreach(fun(BreakInfo) -> - case BreakInfo#breakInfo.point of - {Mod2, Line} when Mod2 =:= Mod -> - Status = BreakInfo#breakInfo.status, - add_break_to_code(Editor, Line,Status); - _Point -> ignore - end - end, - WinInfo#winInfo.breaks), - case Flag of - existing -> - WinInfo#winInfo{editor={Mod, Editor}}; - new -> - WinInfo#winInfo{editor={Mod, Editor}, - editors=[{Mod, Editor} | Editors]} - end. - -show_code(Editor, Text) when length(Text) > 1500 -> - %% Add some text at a time so that other processes may get scheduled - Str = string:sub_string(Text, 1, 1500), - config_editor(Editor, {insert,{'end', Str}}), - show_code(Editor, string:sub_string(Text, 1501)); -show_code(Editor, Text) -> - config_editor(Editor, {insert,{'end',Text}}). - -show_no_code(WinInfo) -> - {'$top', Editor} = lists:keyfind('$top', 1, WinInfo#winInfo.editors), - gs:config(Editor, raise), - WinInfo#winInfo{editor={'$top', Editor}}. - -remove_code(WinInfo, Mod) -> - Editors = WinInfo#winInfo.editors, - case lists:keyfind(Mod, 1, Editors) of - {Mod, Editor} -> - gs:destroy(Editor), - WinInfo#winInfo{editors=lists:keydelete(Mod, 1, Editors)}; - false -> - WinInfo - end. - -%%-------------------------------------------------------------------- -%% mark_line(WinInfo, Line, How) -> WinInfo -%% WinInfo = #winInfo{} -%% Line = integer() -%% How = break | where -%% Mark the code line where the process is executing. -%%-------------------------------------------------------------------- -mark_line(WinInfo, Line, How) -> - {_Mod, Editor} = WinInfo#winInfo.editor, - mark_line2(Editor, WinInfo#winInfo.marked_line, false), - mark_line2(Editor, Line, How), - if - Line =/= 0 -> config_editor(Editor, {vscrollpos, Line-5}); - true -> ignore - end, - WinInfo#winInfo{marked_line=Line}. - -unmark_line(WinInfo) -> - mark_line(WinInfo, 0, false). - -mark_line2(Editor, Line, How) -> - Prefix = case How of - break -> "-->"; - where -> ">>>"; - false -> " " - end, - Font = if - How =:= false -> dbg_ui_win:font(normal); - true -> dbg_ui_win:font(bold) - end, - config_editor(Editor, [{overwrite, {{Line,5}, Prefix}}, - {font_style, - {{{Line,0},{Line,lineend}}, Font}}]). - -%%-------------------------------------------------------------------- -%% select_line(WinInfo, Line) -> WinInfo -%% selected_line(WinInfo) -> undefined | Line -%% WinInfo = #winInfo{} -%% Line = integer() -%% Select/unselect a line (unselect if Line=0). -%%-------------------------------------------------------------------- -select_line(WinInfo, Line) -> - {_Mod, Editor} = WinInfo#winInfo.editor, - - %% Since 'Line' may be specified by the user in the 'Go To Line' - %% help window, it must be checked that it is correct - Size = gs:read(Editor, size), - if - Line =:= 0 -> - select_line(Editor, WinInfo#winInfo.selected_line, false), - WinInfo#winInfo{selected_line=0}; - Line < Size -> - select_line(Editor, Line, true), - config_editor(Editor, {vscrollpos, Line-5}), - WinInfo#winInfo{selected_line=Line}; - true -> - WinInfo - end. - -select_line(Editor, Line, true) -> - config_editor(Editor, {selection, {{Line,0}, {Line,lineend}}}); -select_line(Editor, _Line, false) -> - config_editor(Editor, {selection, {{1,0}, {1,0}}}). - -selected_line(WinInfo) -> - case WinInfo#winInfo.selected_line of - 0 -> undefined; - Line -> Line - end. - -%%-------------------------------------------------------------------- -%% eval_output(Str, Face) -%% Str = string() -%% Face = normal | bold -%%-------------------------------------------------------------------- -eval_output(Text, Face) -> - Y1 = gs:read('EvalEditor', size), - config_editor('EvalEditor', {insert,{'end',Text}}), - Y2 = gs:read('EvalEditor', size), - - Font = dbg_ui_win:font(Face), - config_editor('EvalEditor', - [{font_style, {{{Y1,0},{Y2,lineend}}, Font}}, - {vscrollpos,Y2}]). - -%%-------------------------------------------------------------------- -%% update_bindings(Bs) -%% Bs = [{Var,Val}] -%%-------------------------------------------------------------------- -update_bindings(Bs) -> - gs:config('BindGrid', {rows, {1,length(Bs)+1}}), - Font = dbg_ui_win:font(normal), - Last = - lists:foldl(fun({Var, Val}, Row) -> - Opts = [{text, {1,atom_to_list(Var)}}, - {text, {2,io_lib:format("~P", - [Val, 4])}}, - {doubleclick, true}, - {data, {binding,{Var,Val}}}], - case gs:read('BindGrid',{obj_at_row,Row}) of - undefined -> - gs:gridline('BindGrid', - [{row, Row}, - {height, 14}, - {font, Font} | Opts]); - GridLine -> - gs:config(GridLine, Opts) - end, - Row+1 - end, - 2, - Bs), - delete_gridlines(Last). - -delete_gridlines(Row) -> - case gs:read('BindGrid', {obj_at_row, Row}) of - undefined -> true; - GridLine -> - gs:destroy(GridLine), - delete_gridlines(Row+1) - end. - -%%-------------------------------------------------------------------- -%% trace_output(Str) -%% Str = string() -%%-------------------------------------------------------------------- -trace_output(Str) -> - Font = dbg_ui_win:font(normal), - config_editor('TraceEditor', - [{insert, {'end',Str}}, - {fg, {{{1,0},'end'},black}}, - {font_style, {{{1,0},'end'},Font}}]), - Max = gs:read('TraceEditor', size), - config_editor('TraceEditor', {vscrollpos, Max}). - -%%-------------------------------------------------------------------- -%% handle_event(GSEvent, WinInfo) -> Command -%% GSEvent = {gs, Id, Event, Data, Arg} -%% WinInfo = #winInfo{} -%% Command = ignore -%% | {win, WinInfo} -%% | stopped -%% | {coords, {X,Y}} -%% -%% | {shortcut, Key} -%% | MenuItem | {Menu, [MenuItem]} -%% MenuItem = Menu = atom() -%% | {break, Point, What} -%% What = add | delete | {status,Status} |{trigger,Trigger} -%% | {module, Mod, view} -%% -%% | {user_command, Cmd} -%% -%% | {edit, {Var, Val}} -%%-------------------------------------------------------------------- -%% Window events -handle_event({gs, _Id, configure, _Data, [W, H|_]}, WinInfo) -> - case WinInfo#winInfo.size of - {W, H} -> ignore; - _Size -> - configure(WinInfo, W, H), - {win, WinInfo#winInfo{size={W, H}}} - end; -handle_event({gs, _Id, destroy, _Data, _Arg}, _WinInfo) -> - stopped; -handle_event({gs, _Id, motion, _Data, [X,Y]}, WinInfo) -> - {LastX, LastY} = dbg_ui_win:motion(X, Y), - Win = WinInfo#winInfo.window, - {coords, {gs:read(Win, x)+LastX-5, gs:read(Win, y)+LastY-5}}; -handle_event({gs, RB, buttonpress, resizebar, _Arg}, WinInfo) -> - resize(WinInfo, RB), % Resize window contents - ignore; - -%% Menus, buttons and keyboard shortcuts -handle_event({gs, _Id, keypress, _Data, [Key,_,_,1]}, _WinInfo) -> - {shortcut, Key}; -handle_event({gs, _Id, click, {dbg_ui_winman, Win}, _Arg}, _WinInfo) -> - dbg_ui_winman:raise(Win), - ignore; -handle_event({gs, _Id, click, {menuitem, Name}, _Arg}, _WinInfo) -> - Name; -handle_event({gs, _Id, click, {menu, Menu}, _Arg}, _WinInfo) -> - Names = dbg_ui_win:selected(Menu), - {Menu, Names}; -handle_event({gs, _Id, click, {break, Point, What}, _Arg}, _WinInfo) -> - {break, Point, What}; -handle_event({gs, _Id, click, {module, Mod, view}, _Arg}, _WinInfo) -> - {module, Mod, view}; - -%% Code area -handle_event({gs, Editor, buttonpress, code_editor, _Arg}, WinInfo) -> - {Row, _Col} = gs:read(Editor, insertpos), - Again = receive - {gs, Editor, buttonpress, code_editor, _} -> - gs:read(Editor, insertpos) - after 500 -> - false - end, - case Again of - {Row, _} -> - {Mod, _Editor} = WinInfo#winInfo.editor, - Point = {Mod, Row}, - case lists:keymember(Point, #breakInfo.point, - WinInfo#winInfo.breaks) of - false -> {break, Point, add}; - true -> {break, Point, delete} - end; - {Row2, _} -> - select_line(Editor, Row2, true), - {win, WinInfo#winInfo{selected_line=Row2}}; - false -> - select_line(Editor, Row, true), - {win, WinInfo#winInfo{selected_line=Row}} - end; - -%% Button area -handle_event({gs, _Id, click, {button, Name}, _Arg}, _WinInfo) -> - Name; - -%% Evaluator area -handle_event({gs, 'EvalEntry', keypress, _Data, ['Return'|_]}, _WI) -> - Command = case gs:read('EvalEntry', text) of - [10] -> - eval_output("\n", normal), - ignore; - Cmd -> - eval_output([$>, Cmd, 10], normal), - {user_command, Cmd} - end, - gs:config('EvalEntry', [{text,""}, {focus,false}]), - Command; - -%% Bindings area -handle_event({gs, _Id, click, {binding, {Var, Val}}, _Arg}, _WinInfo) -> - Str = io_lib:format("< ~p = ~p~n", [Var, Val]), - eval_output(Str, bold), - ignore; -handle_event({gs, _Id, doubleclick, {binding, B}, _Arg}, _WinInfo) -> - {edit, B}; - -handle_event(_GSEvent, _WinInfo) -> - ignore. - - -%%==================================================================== -%% Internal functions -%%==================================================================== - -%%--Code Area--------------------------------------------------------- - -code_area(X, Y, FrameOpts, Win) -> - gs:frame('CodeArea', Win, - [{x,X}, {y,Y}, {width,546}, {height,400} | FrameOpts]), - gs:label(info_window, 'CodeArea', - [{label,{text,""}}, {font,dbg_ui_win:font(normal)}, - {x,5}, {y,10}, {width,406}, {height,15}, - {anchor,nw}, {align,w}]), - code_editor('CodeEditor', 536, 365). - -code_editor() -> - W = gs:read('CodeEditor', width), - H = gs:read('CodeEditor', height), - code_editor(null, W, H). - -code_editor(Name, W, H) -> - Editor = if - Name =:= null -> gs:editor('CodeArea', []); - true -> gs:editor(Name, 'CodeArea', []) - end, - gs:config(Editor, [{x,5}, {y,30}, {width,W}, {height,H}, - {keypress,false}, {buttonpress,true}, - {data,code_editor}]), - config_editor(Editor, [{vscroll,right}, {hscroll,bottom}]), - Font = dbg_ui_win:font(normal), - config_editor(Editor, [{wrap,none}, {fg,{{{1,0},'end'},black}}, - {font, Font}, - {font_style, {{{1,0},'end'},Font}}]), - Editor. - -resize_code_area(WinInfo, Key, Diff) -> - gs:config('CodeArea', {Key,gs:read('CodeArea', Key)+Diff}), - case Key of - width -> - gs:config(info_window, {Key,gs:read(info_window,Key)+Diff}); - height -> ignore - end, - - %% Resize all code editors - Value = gs:read('CodeEditor', Key)+Diff, - gs:config('CodeEditor', {Key,Value}), - Editors = WinInfo#winInfo.editors, - lists:foreach(fun({_Mod, Editor}) -> - gs:config(Editor, {Key,Value}) - end, - Editors). - -%%--Button Area------------------------------------------------------- - -buttons() -> - [{'Step','StepButton'}, {'Next','NextButton'}, - {'Continue','ContinueButton'}, {'Finish','FinishButton'}, - {'Where','WhereButton'}, {'Up','UpButton'}, {'Down','DownButton'}]. - -is_button(Name) -> - case lists:keyfind(Name, 1, buttons()) of - {Name, Button} -> {true, Button}; - false -> false - end. - -button_area(Bu, X, Y, FrameOpts, Win) -> - {W,H} = case Bu of - open -> {546,30}; - close -> {0,0} - end, - gs:frame('ButtonArea', Win, - [{x,X}, {y,Y}, {width,W}, {height,H} | FrameOpts]), - Font = dbg_ui_win:font(normal), - lists:foldl(fun({Name, Button}, Xb) -> - gs:button(Button, 'ButtonArea', - [{label, {text,Name}}, {font,Font}, - {x, Xb}, {y, 1}, - {width, 77}, {height, 24}, - {data, {button,Name}}]), - Xb+78 - end, - 1, - buttons()). - -resize_button_area(close, width, _Diff) -> - ignore; -resize_button_area(open, width, Diff) -> - gs:config('ButtonArea', {width, gs:read('ButtonArea', width)+Diff}). - -%%--Evaluator Area---------------------------------------------------- - -eval_area({Ev,Bi}, X, Y, FrameOpts, Win) -> - {W,H} = if - Ev =:= open -> {289,200}; - true -> {0,0} - end, - Font = dbg_ui_win:font(normal), - gs:frame('EvalArea', Win, - [{x,X}, {y,Y}, {width,W}, {height,H} | FrameOpts]), - gs:label('EvalArea', - [{label,{text,"Evaluator:"}}, {font, Font}, - {x,5}, {y,35}, {width,80}, {height,25}, - {anchor,sw}, {align,center}]), - gs:entry('EvalEntry', 'EvalArea', - [{font, Font}, - {x,80}, {y,35}, {width,185}, {height,25}, - {anchor,sw}, {keypress,true}]), - gs:editor('EvalEditor', 'EvalArea', - [{x,5}, {y,35}, {width, 280}, {height, 160}, - {keypress,false}, - {vscroll,right}, {hscroll,bottom}, - {wrap,none}, {fg,{{{1,0},'end'},black}}, - {font, Font}, - {font_style,{{{1,0},'end'},Font}}]), - gs:config('EvalEditor', {enable, false}), - if - Ev =:= open, Bi =:= close -> resize_eval_area(Ev, width, 257); - true -> ignore - end. - -resize_eval_area(close, _Key, _Diff) -> - ignore; -resize_eval_area(open, Key, Diff) -> - New = gs:read('EvalArea', Key)+Diff, - gs:config('EvalArea', {Key,New}), - case Key of - width -> - gs:config('EvalEntry', {width,New-104}), - gs:config('EvalEditor', {width,New-9}); - height -> - gs:config('EvalEditor', {height,New-40}) - end. - -%%--Bindings Area----------------------------------------------------- - -bind_area({Ev,Bi}, X, Y, FrameOpts, Win) -> - {W,H} = if - Bi =:= open -> {249,200}; - true -> {0,0} - end, - gs:frame('BindArea', Win, - [{x,X}, {y,Y}, {width,W}, {height,H} | FrameOpts]), - - Font = dbg_ui_win:font(bold), - gs:grid('BindGrid', 'BindArea', - [{x,2}, {y,2}, {height,193}, {width,241}, - {fg,black}, {vscroll,right}, {hscroll,bottom}, - {font,Font}, - calc_columnwidths(241), {rows, {1,50}}]), - gs:gridline('BindGrid', - [{row,1}, {height,14}, {fg,blue}, - {text,{1,"Name"}}, {text,{2,"Value"}}, {font,Font}]), - gs:config('BindGrid', {rows,{1,1}}), - if - Bi =:= open, Ev =:= close -> resize_bind_area(Bi, width, 297); - true -> ignore - end. - -resize_bind_area(close, _Key, _Diff) -> - ignore; -resize_bind_area(open, Key, Diff) -> - New = gs:read('BindArea', Key)+Diff, - gs:config('BindArea', {Key,New}), - case Key of - width -> - gs:config('BindGrid', {width,New-8}), - Cols = calc_columnwidths(New-8), - gs:config('BindGrid', Cols); - height -> - gs:config('BindGrid', {height,New-7}) - end. - -calc_columnwidths(Width) -> - if Width =< 291 -> - {columnwidths,[90,198]}; - true -> - S = (Width)/(90+198), - {columnwidths,[round(90*S),round(198*S)]} - end. - -%%--Trace Area-------------------------------------------------------- - -trace_area(Tr, X, Y, FrameOpts, Win) -> - {W,H} = case Tr of - open -> {546,200}; - close -> {0,0} - end, - gs:frame('TraceArea', Win, - [{x,X}, {y,Y}, {width,W}, {height,H} | FrameOpts]), - Editor = gs:editor('TraceEditor', 'TraceArea', - [{x,5}, {y,5}, {width,536}, {height,190}, - {keypress,false}]), - Font = dbg_ui_win:font(normal), - config_editor(Editor, - [{vscroll,right}, {hscroll,bottom}, - {wrap,none},{fg,{{{1,0},'end'},black}}, - {font, Font}, - {font_style,{{{1,0},'end'},Font}}]). - -resize_trace_area(close, _Key, _Diff) -> - ignore; -resize_trace_area(open, Key, Diff) -> - New = gs:read('TraceArea', Key)+Diff, - gs:config('TraceArea', {Key,New}), - gs:config('TraceEditor', {Key,New-10}). - -%%--Editors----------------------------------------------------------- - -config_editor(Editor, Opts) -> - gs:config(Editor, {enable,true}), - gs:config(Editor, Opts), - gs:config(Editor, {enable,false}). - -%%--Resize Bars------------------------------------------------------- -%% The resize bars are used to resize the areas within the window. - -%%-------------------------------------------------------------------- -%% resizebar(Flag, Name, X, Y, W, H, Obj) -> resizebar() -%% Flag = open | close -%% Name = atom() -%% X = Y = integer() Coordinates relative to Obj -%% W = H = integer() Width and height -%% Obj = gsobj() -%% Creates a 'resize bar', a frame object over which the cursor will -%% be of the 'resize' type. -%%-------------------------------------------------------------------- -resizebar(Flag, Name, X, Y, W, H, Obj) -> - {W2,H2} = case Flag of - open -> {W,H}; - close -> {0,0} - end, - gs:create(frame, Name, Obj, [{x,X}, {y,Y}, {width,W2}, {height,H2}, - {bw,2}, - {cursor,resize}, - {buttonpress,true}, {buttonrelease,true}, - {data,resizebar}]). - -rb1({_Bu,Ev,Bi,Tr}) -> - if - Ev =:= close, Bi =:= close, Tr =:= close -> close; - true -> open - end. - -rb2({_Bu,Ev,Bi,Tr}) -> - if - Tr =:= open -> - if - Ev =:= close, Bi =:= close -> close; - true -> open - end; - true -> close - end. - -rb3({_Bu,Ev,Bi,_Tr}) -> - if - Ev =:= open, Bi =:= open -> open; - true -> close - end. - -%%--Configuration----------------------------------------------------- -%% Resize the window as well as its contents - -%%-------------------------------------------------------------------- -%% config_v() -%% Reconfigure the window vertically. -%%-------------------------------------------------------------------- -config_v() -> - Y1 = 25+gs:read('CodeArea', height), - gs:config('RB1', {y,Y1}), - - Y2 = Y1+gs:read('RB1', height), - gs:config('ButtonArea', {y,Y2}), - - Y3 = Y2+gs:read('ButtonArea', height), - gs:config('EvalArea', {y,Y3}), - gs:config('RB3', {y,Y3}), - gs:config('BindArea', {y,Y3}), - - Y4 = Y3 + erlang:max(gs:read('EvalArea', height), - gs:read('BindArea', height)), - gs:config('RB2', {y,Y4}), - - Y5 = Y4 + gs:read('RB2', height), - gs:config('TraceArea', {y,Y5}). - -%%-------------------------------------------------------------------- -%% config_h() -%% Reconfigure the window horizontally. -%%-------------------------------------------------------------------- -config_h() -> - X1 = 2+gs:read('EvalArea', width), - gs:config('RB3', {x,X1}), - - X2 = X1+gs:read('RB3', width), - gs:config('BindArea', {x,X2}). - -%%-------------------------------------------------------------------- -%% configure(WinInfo, W, H) -%% The window has been resized, now its contents must be resized too. -%%-------------------------------------------------------------------- -configure(WinInfo, NewW, NewH) -> - {Bu,Ev,Bi,Tr} = Flags = WinInfo#winInfo.flags, - - OldW = gs:read('CodeArea', width)+4, - OldH = 25+gs:read('CodeArea', height)+ - gs:read('RB1', height)+ - gs:read('ButtonArea', height)+ - erlang:max(gs:read('EvalArea', height), gs:read('BindArea', height))+ - gs:read('RB2', height)+ - gs:read('TraceArea', height), - - %% Adjust width unless it is unchanged or less than minimum width - if - OldW =/= NewW -> - {Dcode,Deval,Dbind} = configure_widths(OldW,NewW,Flags), - resize_code_area(WinInfo, width, Dcode), - case rb1(Flags) of - open -> - gs:config('RB1', {width,gs:read('RB1',width)+Dcode}); - close -> ignore - end, - resize_button_area(Bu, width, Dcode), - resize_eval_area(Ev, width, Deval), - resize_bind_area(Bi, width, Dbind), - case rb2(Flags) of - open -> - gs:config('RB2', {width,gs:read('RB2',width)+Dcode}); - close -> ignore - end, - resize_trace_area(Tr, width, Dcode), - config_h(); - true -> ignore - end, - - %% Adjust height unless it is unchanged or less than minimum height - if - OldH =/= NewH -> - {Dcode2,Deval2,Dtrace} = configure_heights(OldH,NewH,Flags), - resize_code_area(WinInfo, height, Dcode2), - resize_eval_area(Ev, height, Deval2), - case rb3(Flags) of - open -> - gs:config('RB3', - {height,gs:read('RB3',height)+Deval2}); - close -> ignore - end, - resize_bind_area(Bi, height, Deval2), - resize_trace_area(Tr, height, Dtrace), - config_v(); - true -> ignore - end. - -%% Compute how much the width of each frame must be increased or -%% decreased in order to adjust to the new window width. -configure_widths(OldW, NewW, Flags) -> - {_Bu,Ev,Bi,_Tr} = Flags, - - %% Difference between old and new width, considering min window width - Diff = abs(erlang:max(OldW,330)-erlang:max(NewW,330)), - - %% Check how much the frames can be resized in reality - Limits = if - %% Window larger - NewW > OldW -> - if - Ev =:= open, Bi =:= open -> {0,Diff,Diff}; - Ev =:= open -> {0,Diff,0}; - Bi =:= open -> {0,0,Diff}; - true -> {Diff,0,0} - end; - - %% Window smaller; get difference between min size - %% and current size - OldW>NewW -> - if - Ev =:= open, Bi =:= open -> - {0, - gs:read('EvalArea',width)-204, - gs:read('BindArea',width)-112}; - Ev =:= open -> {0,Diff,0}; - Bi =:= open -> {0,0,Diff}; - true -> {Diff,0,0} - end - end, - - case Limits of - - %% No Shell or Bind frame, larger window - {T,0,0} when NewW > OldW -> {T,0,0}; - - %% No Shell or Bind frame, smaller window - {T,0,0} when OldW > NewW -> {-T,0,0}; - - %% Window larger; divide Diff among the frames and return result - {_,Sf,B} when NewW > OldW -> - {_,Sf2,B2} = divide([{0,0},{0,Sf},{0,B}],Diff), - {Sf2+B2,Sf2,B2}; - - %% Window smaller; divide Diff among the frames and return - %% the inverted result (the frames should shrink) - {_,Sf,B} when OldW>NewW -> - {_,Sf2,B2} = divide([{0,0},{0,Sf},{0,B}],Diff), - {-(Sf2+B2),-Sf2,-B2} - end. - -%% Compute how much the height of each frame must be increased or -%% decreased in order to adjust to the new window height. -configure_heights(OldH, NewH, Flags) -> - {_Bu,Ev,Bi,Tr} = Flags, - - %% Difference between old and new height, considering min win height - MinH = min_height(Flags), - Diff = abs(erlang:max(OldH,MinH)-erlang:max(NewH,MinH)), - - %% Check how much the frames can be resized in reality - {T,Sf,Ff} = if - %% Window larger - NewH > OldH -> - {Diff, - if - Ev =:= close, Bi =:= close -> 0; - true -> Diff - end, - if - Tr =:= open -> Diff; - true -> 0 - end}; - - %% Window smaller; get difference between min size - %% and current size - OldH > NewH -> - {gs:read('CodeArea',height)-100, - if - Ev =:= close, Bi =:= close -> 0; - true -> - if - Ev =:= open -> - gs:read('EvalArea',height)-100; - Bi =:= open -> - gs:read('BindArea',height)-100 - end - end, - if - Tr =:= open -> gs:read('TraceArea',height)-100; - true -> 0 - end} - end, - - if - %% Window larger; divide Diff among the frames and return result - NewH>OldH -> divide([{0,T},{0,Sf},{0,Ff}],Diff); - - %% Window smaller; divide Diff among the frames and return - %% the inverted result (the frames should shrink) - OldH>NewH -> - {T2,Sf2,Ff2} = divide([{0,T},{0,Sf},{0,Ff}],Diff), - {-T2,-Sf2,-Ff2} - end. - -%% Compute minimum window height -min_height(Flags) -> - {Bu,S,Bi,F} = Flags, - H1 = 25 + 100 + 2, % Upper pad + Trace frame + lower pad - H2 = H1 + bu(Bu) + s_bi(S,Bi) + f(F), - H3 = case rb1(Flags) of - open -> H2+10; - close -> H2 - end, - H4 = case rb2(Flags) of - open -> H3+10; - close -> H3 - end, - H4. - -bu(close) -> 0; -bu(open) -> 30. - -s_bi(close,close) -> 0; -s_bi(_,_) -> 100. - -f(close) -> 0; -f(open) -> 100. - -%% Try to distribute Diff as evenly as possible between E1, E2 and E3. -divide([{T,T},{S,S},{F,F}], _Diff) -> - {T,S,F}; -divide(L, Diff) -> - [{T,Tmax},{S,Smax},{F,Fmax}] = L, - - %% Count how many elements in L can still be filled - Rem = remaining(L), - - %% Divide Diff by Rem - D = Diff div Rem, - - if - %% All of Diff has been distributed - D =:= 0 -> {T,S,F}; - true -> - %% For each element, try to add as much as possible of D - {NewT,Dt} = divide2(D,T,Tmax), - {NewS,Ds} = divide2(D,S,Smax), - {NewF,Df} = divide2(D,F,Fmax), - - %% Recur with a list of elements with new current values - %% and decreased Diff - divide([{NewT,Tmax},{NewS,Smax},{NewF,Fmax}], - (Diff rem Rem)+Dt+Ds+Df) - end. - -%% Count the number of 'non-filled' elements in L, ie where Curr<Max. -remaining([]) -> 0; -remaining([{Max,Max}|T]) -> remaining(T); -remaining([_H|T]) -> 1 + remaining(T). - -divide2(_Diff, Max, Max) -> {Max,0}; -divide2(Diff, Curr, Max) -> - New = Curr+Diff, - if - New>Max -> {Max,New-Max}; - true -> {New,0} - end. - -%%--Resizing using resize bars---------------------------------------- -%% Motions event will move the ResizeBar accordingly in Win, when -%% the mouse button is released, the window is reconfigured. - -resize(WinInfo, ResizeBar) -> - - %% Get window dimensions - W = gs:read(WinInfo#winInfo.window, width), - H = gs:read(WinInfo#winInfo.window, height), - - %% Call resize loop with min and max for the resize bars derived - %% from the window dimensions - resizeloop(WinInfo, ResizeBar, null, - rblimits('RB1',W,H), - rblimits('RB2',W,H), - rblimits('RB3',W,H)). - -resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}) -> - receive - {gs,_,motion,_,[_,Y]} when RB =:= 'RB1', Y > Min1, Y < Max1 -> - gs:config('RB1', {y,Y}), - resizeloop(WI, RB, Y, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}); - {gs,_,motion,_,_} when RB =:= 'RB1' -> - resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}); - - {gs,_,motion,_,[_,Y]} when RB =:= 'RB2', Y > Min2, Y < Max2 -> - gs:config('RB2', {y,Y}), - resizeloop(WI, RB, Y, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}); - {gs,_,motion,_,_} when RB =:= 'RB2' -> - resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}); - - {gs,_,motion,_,[X,_]} when RB =:= 'RB3', X > Min3, X < Max3 -> - gs:config('RB3', {x,X}), - resizeloop(WI, RB, X, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}); - {gs,_,motion,_,_} when RB =:= 'RB3' -> - resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}); - - {gs,_,buttonrelease,_,_} -> - resize_win(WI, RB, Prev) - end. - -resize_win(_WinInfo, _RB, null) -> ignore; -resize_win(WinInfo, 'RB1', Y) -> - {_Bu,S,Bi,F} = Flags = WinInfo#winInfo.flags, - H = gs:read('CodeArea', height), - Diff = H-(Y-25), - - %% Resize Code, Evaluator and Binding areas - resize_code_area(WinInfo, height, -Diff), - if - S =:= close, Bi =:= close, F =:= open -> - resize_trace_area(open, height, Diff); - true -> - resize_eval_area(S, height, Diff), - resize_bind_area(Bi, height, Diff) - end, - - %% Resize vertical resize bar - case rb3(Flags) of - open -> gs:config('RB3', {height,gs:read('RB3',height)+Diff}); - close -> ignore - end, - - %% Adjust the frames y coordinates - config_v(); -resize_win(WinInfo, 'RB2', Y) -> - {_Bu,S,Bi,F} = Flags = WinInfo#winInfo.flags, - Prev = gs:read('TraceArea',y), - Diff = Prev-(Y+10), - - %% Resize Trace, Evaluator and Binding areas - resize_trace_area(F, height, Diff), - resize_eval_area(S, height, -Diff), - resize_bind_area(Bi, height, -Diff), - - %% Resize vertical resize bar - case rb3(Flags) of - open -> gs:config('RB3', {height,gs:read('RB3',height)-Diff}); - close -> ignore - end, - - %% Adjust the frames y coordinates - config_v(); - -resize_win(WinInfo, 'RB3', X) -> - {_Bu,S,Bi,_F} = WinInfo#winInfo.flags, - Prev = gs:read('BindArea', x), - Diff = Prev-(X+10), - - %% Resize Binding and Trace areas - resize_bind_area(Bi, width, Diff), - resize_eval_area(S, width, -Diff), - - %% Adjust the frames x coordinates - config_h(). - -%% Given the window dimensions, return the limits for a resize bar. -rblimits('RB1',_W,H) -> - - %% Code frame should not have height <100 - Min = 126, - - %% Max is decided by a minimum distance to 'RB2' - %% unless 'RB2' is invisible and 'CodeArea' is visible - %% (=> EvalFrame and BindFrame invisible) in which case - %% TraceFrame should not have height <100 - RB2 = gs:read('RB2',height), - FF = gs:read('TraceArea',height), - Max = case RB2 of - 0 when FF =/= 0 -> - H-112; - _ -> - Y = gs:read('RB2',y), - erlang:max(Min,Y-140) - end, - - {Min,Max}; -rblimits('RB2',_W,H) -> - %% TraceFrame should not have height < 100 - Max = H-112, - %% Min is decided by a minimum distance to 'RB1' - Y = gs:read('RB1',y), - Min = erlang:min(Max,Y+140), - {Min,Max}; - -rblimits('RB3',W,_H) -> - %% Neither CodeArea nor BindArea should occupy - %% less than 1/3 of the total window width and EvalFrame should - %% be at least 289 pixels wide - {erlang:max(round(W/3),289),round(2*W/3)}. - - -%%==================================================================== -%% 'Go To Line' and 'Search' help windows -%%==================================================================== - -helpwin(gotoline, WinInfo, GS, Coords) -> - spawn_link(?MODULE, helpwin, [gotoline, WinInfo, GS, Coords,self()]); -helpwin(search, WinInfo, GS, Coords) -> - spawn_link(?MODULE, helpwin, [search, WinInfo, GS, Coords, self()]). - -helpwin(Type, WinInfo, GS, Coords, AttPid) -> - {_Mod, Editor} = WinInfo#winInfo.editor, - Data = case Type of - gotoline -> null; - search -> - {{1, 0}, false} - end, - Win = helpwin(Type, GS, Coords), - helpwin_loop(Type, AttPid, Editor, Data, Win). - -helpwin_loop(Type, AttPid, Editor, Data, Win) -> - receive - {gs, _Id, destroy, _Data, _Arg} -> - helpwin_stop(Type, AttPid, Editor, Data), - true; - - {gs, _Id, keypress, _Data, ['Return'|_]} -> - gs:config(btn(Win), flash), - Data2 = helpwin_action(Type, default, - AttPid, Editor, Data, Win), - helpwin_loop(Type, AttPid, Editor, Data2, Win); - {gs, _Id, keypress, _Data, _Arg} -> - helpwin_loop(Type, AttPid, Editor, Data, Win); - - {gs, _Id, click, _Data, ["Clear"]} -> - gs:config(ent(Win), {delete, {0,last}}), - Data2 = helpwin_clear(Type, AttPid, Editor, Data, Win), - helpwin_loop(Type, AttPid, Editor, Data2, Win); - {gs, _Id, click, _Data, ["Close"]} -> - helpwin_stop(Type, AttPid, Editor, Data), - true; - {gs, _Id, click, Action, _Arg} -> - Data2 = - helpwin_action(Type, Action, AttPid, Editor, Data, Win), - helpwin_loop(Type, AttPid, Editor, Data2, Win) - end. - -helpwin_stop(gotoline, _AttPid, _Editor, _Data) -> - ignore; -helpwin_stop(search, _AttPid, Editor, {Pos, _CS}) -> - unmark_string(Editor, Pos). - -helpwin_clear(gotoline, _AttPid, _Editor, Data, _Win) -> - Data; -helpwin_clear(search, _AttPid, Editor, {Pos, CS}, Win) -> - unmark_string(Editor, Pos), - gs:config(lbl(Win), {label, {text,""}}), - {{1, 0}, CS}. - -helpwin_action(gotoline, default, AttPid, _Editor, Data, Win) -> - case string:strip(gs:read(ent(Win), text)) of - "" -> ignore; - Str -> - case catch list_to_integer(Str) of - {'EXIT', _Reason} -> ignore; - Line -> AttPid ! {gui, {gotoline, Line}} - end - end, - Data; -helpwin_action(search, case_sensitive, _AttPid, _Ed, {Pos, CS}, _Win) -> - Bool = if CS =:= true -> false; CS =:= false -> true end, - {Pos, Bool}; -helpwin_action(search, default, _AttPid, Editor, {Pos, CS}, Win) -> - gs:config(lbl(Win), {label, {text, ""}}), - unmark_string(Editor, Pos), - case gs:read(ent(Win), text) of - "" -> {Pos, CS}; - Str -> - gs:config(lbl(Win), {label, {text,"Searching..."}}), - Str2 = lowercase(CS, Str), - case search(Str2, Editor, gs:read(Editor, size), Pos, CS) of - {Row, Col} -> - gs:config(lbl(Win), {label, {text,""}}), - mark_string(Editor, {Row, Col}, Str), - {{Row, Col}, CS}; - not_found -> - gs:config(lbl(Win), {label, {text,"Not found"}}), - {Pos, CS} - end - end. - -search(_Str, _Editor, Max, {Row, _Col}, _CS) when Row>Max -> - not_found; -search(Str, Editor, Max, {Row, Col}, CS) -> - SearchIn = lowercase(CS, gs:read(Editor, - {get,{{Row,Col+1},{Row,lineend}}})), - case string:str(SearchIn, Str) of - 0 -> search(Str, Editor, Max, {Row+1, 0}, CS); - N -> {Row, Col+N} - end. - -lowercase(true, Str) -> Str; -lowercase(false, Str) -> - [if Char >= $A, Char =< $Z -> Char+32; - true -> Char - end || Char <- Str]. - -mark_string(Editor, {Row, Col}, Str) -> - Between = {{Row,Col}, {Row,Col+length(Str)}}, - Font = dbg_ui_win:font(bold), - gs:config(Editor, [{vscrollpos, Row-5}, - {font_style, {Between, Font}}, - {fg, {Between, red}}]). - -unmark_string(Editor, {Row, Col}) -> - Between = {{Row,Col}, {Row,lineend}}, - Font = dbg_ui_win:font(normal), - gs:config(Editor, [{vscrollpos, Row-5}, - {font_style, {Between, Font}}, - {fg, {Between, black}}]). - -helpwin(Type, GS, {X, Y}) -> - W = 200, Pad = 10, Wbtn = 50, - - Title = case Type of search -> "Search"; gotoline -> "Go To Line" end, - Win = gs:window(GS, [{title, Title}, {x, X}, {y, Y}, {width, W}, - {destroy, true}]), - - Ent = gs:entry(Win, [{x, Pad}, {y, Pad}, {width, W-2*Pad}, - {keypress, true}]), - Hent = gs:read(Ent, height), - - Font = dbg_ui_win:font(normal), - - {Ybtn, Lbl} = - case Type of - search -> - Ycb = Pad+Hent, - gs:checkbutton(Win, [{label, {text, "Case Sensitive"}}, - {font, Font}, - {align, w}, - {x, Pad}, {y, Ycb}, - {width, W-2*Pad}, {height, 15}, - {data, case_sensitive}]), - Ylbl = Ycb+15, - {Ylbl+Hent+Pad, - gs:label(Win, [{x, Pad}, {y, Ylbl}, - {width, W-2*Pad}, {height, Hent}])}; - gotoline -> {Pad+Hent+Pad, null} - end, - - BtnLbl = case Type of search -> "Search"; gotoline -> "Go" end, - Btn = gs:button(Win, [{label, {text, BtnLbl}}, {font, Font}, - {x, W/2-3/2*Wbtn-Pad}, {y, Ybtn}, - {width, Wbtn}, {height, Hent}, - {data, default}]), - gs:button(Win, [{label, {text, "Clear"}}, {font, Font}, - {x, W/2-1/2*Wbtn}, {y, Ybtn}, - {width, Wbtn}, {height, Hent}]), - gs:button(Win, [{label, {text, "Close"}}, {font, Font}, - {x, W/2+1/2*Wbtn+Pad}, {y, Ybtn}, - {width, Wbtn}, {height, Hent}]), - - H = Ybtn+Hent+Pad, - gs:config(Win, [{height, H}, {map, true}]), - {Ent, Lbl, Btn}. - -ent(Win) -> element(1, Win). -lbl(Win) -> element(2, Win). -btn(Win) -> element(3, Win). |