aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger/src/dbg_ui_break_win.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debugger/src/dbg_ui_break_win.erl')
-rw-r--r--lib/debugger/src/dbg_ui_break_win.erl307
1 files changed, 307 insertions, 0 deletions
diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl
new file mode 100644
index 0000000000..a56fe36828
--- /dev/null
+++ b/lib/debugger/src/dbg_ui_break_win.erl
@@ -0,0 +1,307 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. 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_break_win).
+
+%% External exports
+-export([create_win/5,
+ update_functions/2,
+ handle_event/2]).
+
+-record(winInfo, {type, % line | conditional | function
+ win, % gsobj()
+ packer, % gsobj() | undefined
+ entries, % [{atom|integer, GSobj()}]
+ trigger, % enable | disable | delete
+ ok, % gsobj()
+ cancel, % gsobj()
+ listbox, % gsobj()
+ funcs=[] % [[Name, Arity]]
+ }).
+
+%%====================================================================
+%% External exports
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% create_win(GS, Pos, Type, Mod, Line) -> #winInfo{}
+%% GS = graphics system identifier
+%% Pos = {X, Y}
+%% X = Y = integer()
+%% Type = line | conditional | function
+%% Mod = atom() | ""
+%% Line = integer() | ""
+%%--------------------------------------------------------------------
+create_win(GS, {X, Y}, function, Mod, _Line) ->
+ Pad = 8,
+ W = 230,
+
+ Font = dbg_ui_win:font(normal),
+
+ %% Window
+ Win = gs:window(GS, [{title, "Function Break"}, {x, X}, {y, Y},
+ {destroy, true}, {configure, true},
+ {keypress, true}, {data, window}]),
+
+ %% Frame
+ Frm = gs:frame(Win, [{x, 0}, {y, 0}, {width, W}, {height, 190},
+ {packer_x, [{fixed, 70}, {stretch, 1, W-80},
+ {fixed, 10}]},
+ {packer_y, [{fixed, 10}, {fixed, 30},
+ {stretch, 1, 100}, {fixed, 40}]}]),
+
+ %% Create input field (label+entry)
+ gs:label(Frm, [{label, {text,"Module:"}}, {font, Font}, {align, e},
+ {pack_x, 1}, {pack_y, 2}]),
+ Ent = gs:entry(Frm, [{text, Mod},
+ {pack_x, 2}, {pack_y, 2},
+ {keypress, true}, {setfocus, true},
+ {buttonpress, true}]),
+ Entries = [{Ent, atom}],
+
+ %% Create a listbox containing the functions of the module
+ gs:label(Frm, [{label, {text,"Function:"}}, {font, Font}, {align, ne},
+ {pack_x, 1}, {pack_y, 3}]),
+ Lb = gs:listbox(Frm, [{bw, 2}, {relief, ridge}, {vscroll, right},
+ {pack_x, 2}, {pack_y, 3},
+ {selectmode, multiple}]),
+
+ %% Add Ok and Cancel buttons
+ {Wbtn, Hbtn} = dbg_ui_win:min_size(["Ok","Cancel"], 70, 30),
+ Bot = gs:frame(Frm, [{pack_x, {1, 3}}, {pack_y, 4}]),
+ Ok = gs:button(Bot, [{x, Pad}, {y, Pad},
+ {width, Wbtn}, {height, Hbtn},
+ {label, {text,"Ok"}}, {font, Font}]),
+ Cancel = gs:button(Bot, [{x, W-Pad-Wbtn}, {y, Pad},
+ {width, Wbtn}, {height, Hbtn},
+ {label, {text,"Cancel"}}, {font, Font}]),
+
+ Wfrm = gs:read(Frm, width), Hfrm = gs:read(Frm, height),
+ gs:config(Win, [{width, Wfrm}, {height, Hfrm}, {map, true}]),
+ #winInfo{type=function, win=Win,
+ packer=Frm, entries=Entries, trigger=enable,
+ ok=Ok, cancel=Cancel, listbox=Lb, funcs=[]};
+create_win(GS, {X, Y}, Type, Mod, Line) ->
+ Pad = 8,
+ W = 230,
+
+ Font = dbg_ui_win:font(normal),
+
+ %% Window
+ Title = case Type of
+ line -> "Line Break";
+ conditional -> "Conditional Break"
+ end,
+ Win = gs:window(GS, [{title, Title}, {x, X}, {y, Y},
+ {destroy, true}]),
+
+ %% Create input fields (label+entry)
+ {Wlbl, Hlbl} = dbg_ui_win:min_size(["C-Function:"], 10, 30),
+ Went = W-Wlbl-2*Pad,
+ Labels = case Type of
+ line ->
+ [{atom,"Module:",Mod}, {integer,"Line:",Line}];
+ conditional ->
+ [{atom,"Module:",Mod}, {integer,"Line:",Line},
+ {atom,"C-Module:",""}, {atom,"C-Function:",""}]
+ end,
+ Fun = fun({DataType, Label, Default}, Yin) ->
+ gs:create(label, Win, [{x, Pad}, {y, Yin},
+ {width,Wlbl}, {height,Hlbl},
+ {label, {text,Label}},
+ {font, Font}, {align, e}]),
+ Ent = gs:create(entry, Win, [{x, Pad+Wlbl}, {y, Yin},
+ {width, Went},
+ {height, Hlbl},
+ {text, Default},
+ {keypress, true}]),
+ {{Ent, DataType}, Yin+Hlbl}
+ end,
+ {Entries, Yacc} = lists:mapfoldl(Fun, Pad, Labels),
+ {First, _DataType} = hd(Entries),
+ gs:config(First, [{buttonpress, true}, {setfocus, true}]),
+
+ %% Add 'trigger action' buttons
+ {Wlbl2, Hlbl2} = dbg_ui_win:min_size(["Trigger Action"], 100, 20),
+ Wfrm = Wlbl2+8, Hfrm = Hlbl2*4+4,
+ Grp = erlang:now(),
+ Frm = gs:frame(Win, [{x, W/2-Wfrm/2-2}, {y, Yacc+Pad-2},
+ {width, Wfrm}, {height, Hfrm}, {bw, 2}]),
+ gs:label(Frm, [{label, {text, "Trigger Action"}}, {font, Font},
+ {x, 2}, {y, 0}, {width, Wlbl2}, {height, Hlbl2}]),
+ gs:radiobutton(Frm, [{label, {text, "Enable"}}, {font, Font},
+ {x, 10}, {y, Hlbl2},
+ {width, Wlbl2-10}, {height, Hlbl2},
+ {align, w}, {group, Grp},
+ {data, {trigger, enable}},
+ {select, true}]),
+ gs:radiobutton(Frm, [{label, {text, "Disable"}}, {font, Font},
+ {x, 10}, {y, Hlbl2*2},
+ {width, Wlbl2-10}, {height, Hlbl2},
+ {align, w}, {group, Grp},
+ {data, {trigger, disable}}]),
+ gs:radiobutton(Frm, [{label, {text, "Delete"}}, {font, Font},
+ {x, 10}, {y, Hlbl2*3},
+ {width, Wlbl2-10}, {height, Hlbl2},
+ {align, w}, {group, Grp},
+ {data, {trigger, delete}}]),
+
+ %% Add Ok and Cancel buttons
+ {Wbtn, Hbtn} = dbg_ui_win:min_size(["Ok","Cancel"], 70, 30),
+ Ybtn = Yacc + Pad + Hfrm + Pad,
+ Ok = gs:button(Win, [{x, Pad}, {y, Ybtn},
+ {width, Wbtn}, {height, Hbtn},
+ {label, {text,"Ok"}}, {font, Font}]),
+ gs:button(Win, [{x, W-Pad-Wbtn}, {y, Ybtn},
+ {width, Wbtn}, {height, Hbtn},
+ {label, {text,"Cancel"}}, {font, Font}]),
+
+ Hwin = Ybtn + Hbtn + Pad,
+ gs:config(Win, [{width, W}, {height, Hwin}, {map, true}]),
+
+ #winInfo{type=Type, win=Win,
+ entries=Entries, trigger=enable, ok=Ok}.
+
+%%--------------------------------------------------------------------
+%% update_functions(WinInfo, Funcs) -> WinInfo
+%% WinInfo = #winInfo{}
+%% Funcs = [{Name, Arity}]
+%% Name = atom()
+%% Arity = integer()
+%%--------------------------------------------------------------------
+update_functions(WinInfo, Funcs) ->
+ Items = lists:map(fun([N, A]) -> io_lib:format("~p/~p", [N, A]) end,
+ Funcs),
+ gs:config(WinInfo#winInfo.listbox, [{items, Items},
+ {setfocus, true}]),
+ WinInfo#winInfo{funcs=Funcs}.
+
+%%--------------------------------------------------------------------
+%% handle_event(GSEvent, WinInfo) -> Command
+%% GSEvent = {gs, Id, Event, Data, Arg}
+%% WinInfo = #winInfo{}
+%% Command = ignore
+%% | stopped
+%% | {win, WinInfo}
+%% | {module, Mod}
+%% | {break, [[Mod, Line]], Action}
+%% | {break, [[Mod, Line, CMod, CFunc]], Action}
+%% | {break, [[Mod, Func, Arity]], Action}
+%%--------------------------------------------------------------------
+handle_event({gs, _Id, destroy, _Data, _Arg}, _WinInfo) ->
+ stopped;
+handle_event({gs, _Id, configure, _Data, [W, H|_]}, WinInfo) ->
+ gs:config(WinInfo#winInfo.packer, [{width, W-10}, {height, H-10}]),
+ gs:config(WinInfo#winInfo.cancel, [{x, W-80}]),
+ ignore;
+handle_event({gs, Ent, buttonpress, _,[N,X0,Y0|_]}, WinInfo) when N>1 ->
+ %% Right (middle) mouse button click in module entry, display a
+ %% menu containing all interpreted modules
+ Mods = int:interpreted(),
+ X = gs:read(Ent, x) + X0,
+ Y = gs:read(Ent, y) + Y0,
+ Menu = gs:menu(WinInfo#winInfo.win, [{post_at,{X,Y}}]),
+ lists:foreach(fun(Mod) ->
+ gs:menuitem(Menu, [{label,{text,Mod}},
+ {data,{module,Mod}}])
+ end,
+ Mods),
+ ignore;
+handle_event({gs, LB, keypress, window, [Key|_]}, WinInfo) ->
+ %% Used for functional break window, since listboxes for some
+ %% reason doesn't generate keypress events
+ if
+ Key/='Tab', Key/='Return' ->
+ ignore;
+ true ->
+ handle_event({gs, LB, click, listbox, ["Ok"]}, WinInfo)
+ end;
+handle_event({gs, Ent, keypress, Data, [Key|_]}, WinInfo) ->
+ case WinInfo#winInfo.type of
+ function when Key/='Tab', Key/='Return' ->
+ case gs:read(WinInfo#winInfo.listbox, items) of
+ [] -> ignore;
+ _Items ->
+ gs:config(WinInfo#winInfo.listbox, clear),
+ {win, WinInfo#winInfo{funcs=[]}}
+ end;
+ function -> % 'Return' | 'Tab' pressed in Module entry
+ case check_input(WinInfo#winInfo.entries) of
+ error -> ignore;
+ [Mod] -> {module, Mod}
+ end;
+ _Type when Key=='Tab'; Key=='Return' ->
+ case next_entry(Ent, WinInfo#winInfo.entries) of
+ last ->
+ gs:config(WinInfo#winInfo.ok, flash),
+ handle_event({gs, Ent, click, Data, ["Ok"]}, WinInfo);
+ Next ->
+ gs:config(Next, {setfocus, true}),
+ ignore
+ end;
+ _Type -> ignore
+ end;
+handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) ->
+ case check_input(WinInfo#winInfo.entries) of
+ error -> ignore;
+ Data when WinInfo#winInfo.type/=function ->
+ {break, [Data], WinInfo#winInfo.trigger};
+ [Mod] -> % Function break window
+ case gs:read(WinInfo#winInfo.listbox, selection) of
+ [] ->
+ {module, Mod};
+ IndexL ->
+ Funcs = WinInfo#winInfo.funcs,
+ Breaks =
+ lists:map(fun(Index) ->
+ Func = lists:nth(Index+1,
+ Funcs),
+ [Mod | Func]
+ end,
+ IndexL),
+ {break, Breaks, enable}
+ end
+ end;
+handle_event({gs, _Id, click, _Data, ["Cancel"|_]}, _WinInfo) ->
+ stopped;
+handle_event({gs, _Id, click, {trigger,Trigger}, _Arg}, WinInfo) ->
+ {win, WinInfo#winInfo{trigger=Trigger}};
+handle_event({gs, _Id, click, {module, Mod}, _Arg}, WinInfo) ->
+ {Ent, _DataType} = hd(WinInfo#winInfo.entries),
+ gs:config(Ent, {insert,{0,Mod}}),
+ ignore;
+handle_event(_GSEvent, _WinInfo) ->
+ ignore.
+
+check_input(Entries) ->
+ check_input(Entries, []).
+check_input([{Entry, Type} | Entries], Data) ->
+ Str = gs:read(Entry, text),
+ case erl_scan:string(Str) of
+ {ok, [{Type, _Line, Val}], _EndLine} ->
+ check_input(Entries, [Val|Data]);
+ _Error -> error
+ end;
+check_input([], Data) -> lists:reverse(Data).
+
+next_entry(Entry, [{Entry, _Type}]) ->
+ last;
+next_entry(Entry, [{Entry, _Type1}, {Next, _Type2}|_]) ->
+ Next;
+next_entry(Entry, [_|Entries]) ->
+ next_entry(Entry, Entries).