aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger/src/dbg_wx_win.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debugger/src/dbg_wx_win.erl')
-rw-r--r--lib/debugger/src/dbg_wx_win.erl332
1 files changed, 332 insertions, 0 deletions
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
new file mode 100644
index 0000000000..f029990aa4
--- /dev/null
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -0,0 +1,332 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-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_wx_win).
+
+%% External exports
+-export([init/0,
+ create_menus/4, %% For wx
+ add_break/3, update_break/2, delete_break/1,
+ motion/2,
+ confirm/2, notify/2, entry/4, open_help/2,
+ to_string/1, to_string/2,
+ find_icon/1
+ ]).
+
+-record(break, {mb, smi, emi, dimi, demi}).
+-include_lib("wx/include/wx.hrl").
+
+%%====================================================================
+%% External exports
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% init() -> GS
+%% GS = term()
+%%--------------------------------------------------------------------
+init() ->
+ wx:new().
+
+%%--------------------------------------------------------------------
+%% create_menus(MenuBar, [Menu])
+%% MenuBar = gsobj()
+%% Menu = {Name, [Item]}
+%% Name = atom()
+%% Item = {Name, N} | {Name, N, Type} | {Name, N, cascade, [Item]}
+%% | separator
+%% N = no | integer()
+%% Type = check | radio
+%% Create the specified menus and menuitems.
+%%
+%% Normal menuitems are specified as {Name, N}. Generates the event:
+%% {gs, _Id, click, {menuitem, Name}, _Arg}
+%%
+%% Check and radio menuitems are specified as {Name, N, check|radio}.
+%% They are assumed to be children to a cascade menuitem! (And all children
+%% to one cascade menuitem are assumed to be either check OR radio
+%% menuitems)!
+%% Selecting a check/radio menuitem generates the event:
+%% {gs, _Id, click, {menu, Menu}, _Arg}
+%% where Menu is the name of the parent, the cascade menuitem.
+%% Use selected(Menu) to retrieve which check/radio menuitems are
+%% selected.
+%%--------------------------------------------------------------------
+
+create_menus(MB, [{Title,Items}|Ms], Win, Id0) ->
+ Menu = wxMenu:new([]),
+ put(Title,Menu),
+ Id = create_menu_item(Menu, Items, Win, Id0, true),
+ wxMenuBar:append(MB,Menu,menu_name(Title,ignore)),
+ create_menus(MB,Ms,Win,Id);
+create_menus(_MB,[], _Win,Id) -> Id.
+
+create_menu_item(Menu, [separator|Is], Win, Id,Connect) ->
+ wxMenu:appendSeparator(Menu),
+ create_menu_item(Menu,Is,Win,Id+1,Connect);
+create_menu_item(Menu, [{Name, _N, cascade, Items}|Is], Win, Id0,Connect) ->
+ Sub = wxMenu:new([]),
+ Id = create_menu_item(Sub, Items, Win, Id0, false),
+ wxMenu:append(Menu, ?wxID_ANY, menu_name(Name,ignore), Sub),
+ %% Simulate GS sub checkBox/RadioBox behaviour
+ Self = self(),
+ Butts = [{MI,get(MI)} || {MI,_,_} <- Items],
+ IsChecked = fun({MiName,MI},Acc) ->
+ case wxMenuItem:isChecked(MI) of
+ true -> [MiName|Acc];
+ false -> Acc
+ end
+ end,
+ Filter = fun(_,_) ->
+ Enabled = lists:foldl(IsChecked, [], Butts),
+ Self ! #wx{userData={Name, Enabled},
+ event=#wxCommand{type=command_menu_selected}}
+ end,
+ wxMenu:connect(Win, command_menu_selected,
+ [{id,Id0},{lastId, Id-1},{callback,Filter}]),
+ create_menu_item(Menu, Is, Win, Id, Connect);
+create_menu_item(Menu, [{Name,Pos}|Is], Win, Id, Connect) ->
+ Item = wxMenu:append(Menu, Id, menu_name(Name,Pos)),
+ put(Name,Item),
+ if Connect ->
+ wxMenu:connect(Win, command_menu_selected, [{id,Id},{userData, Name}]);
+ true -> ignore
+ end,
+ create_menu_item(Menu,Is,Win,Id+1, Connect);
+create_menu_item(Menu, [{Name,N,check}|Is], Win, Id, Connect) ->
+ Item = wxMenu:appendCheckItem(Menu, Id, menu_name(Name,N)),
+ put(Name,Item),
+ if Connect ->
+ wxMenu:connect(Win, command_menu_selected, [{id,Id},{userData, Name}]);
+ true -> ignore
+ end,
+ create_menu_item(Menu,Is,Win,Id+1,Connect);
+create_menu_item(Menu, [{Name, N, radio}|Is], Win, Id,Connect) ->
+ Item = wxMenu:appendRadioItem(Menu, Id, menu_name(Name,N)),
+ put(Name,Item),
+ if Connect ->
+ wxMenu:connect(Win, command_menu_selected, [{id,Id},{userData, Name}]);
+ true -> ignore
+ end,
+ create_menu_item(Menu,Is,Win,Id+1,Connect);
+create_menu_item(_, [], _, Id,_) ->
+ Id.
+
+%%--------------------------------------------------------------------
+%% add_break(Name, Point) -> #break{}
+%% Name = atom()
+%% Point = {Mod, Line}
+%% The break will generate the following events:
+%% #wx{userData= {break, Point, Event}}
+%% Event = delete | {trigger, Action} | {status, Status}
+%% Action = enable | disable | delete
+%% Status = active | inactive
+%%--------------------------------------------------------------------
+add_break(Win, MenuName, Point) ->
+ %% Create a name for the breakpoint
+ {Mod, Line} = Point,
+ Label = to_string("~w ~5w", [Mod, Line]),
+
+ Menu = get(MenuName),
+ %% Create a menu for the breakpoint
+ Add = fun(Item,Action) ->
+ Id = wxMenuItem:getId(Item),
+ wxMenu:connect(Win, command_menu_selected,
+ [{id,Id}, {userData, Action}])
+ end,
+ Sub = wxMenu:new([]),
+ Dis = wxMenu:append(Sub, ?wxID_ANY, "Disable"),
+ Add(Dis, {break,Point,status}),
+ Del = wxMenu:append(Sub, ?wxID_ANY, "Delete"),
+ Add(Del, {break,Point,delete}),
+ Trigger = wxMenu:new([]),
+ Enable = wxMenu:appendRadioItem(Trigger, ?wxID_ANY,"Enable"),
+ Add(Enable, {break,Point,{trigger,enable}}),
+ TDisable = wxMenu:appendRadioItem(Trigger, ?wxID_ANY,"Disable"),
+ Add(TDisable, {break,Point,{trigger,disable}}),
+ Delete = wxMenu:appendRadioItem(Trigger, ?wxID_ANY,"Delete"),
+ Add(Delete, {break,Point,{trigger,delete}}),
+
+ wxMenu:append(Sub, ?wxID_ANY, "Trigger Action", Trigger),
+ MenuBtn = wxMenu:append(Menu,?wxID_ANY, Label, Sub),
+
+ #break{mb={Menu,MenuBtn},
+ smi=Dis, emi=Enable, dimi=TDisable, demi=Delete}.
+
+%%--------------------------------------------------------------------
+%% update_break(Break, Options)
+%% Break = #break{}
+%% Options = [Status, Action, Mods, Cond]
+%% Status = active | inactive
+%% Action = enable | disable | delete
+%% Mods = null (not used)
+%% Cond = null | {Mod, Func}
+%%--------------------------------------------------------------------
+update_break(Break, Options) ->
+ [Status, Trigger|_] = Options,
+
+ Label = case Status of
+ active -> "Disable";
+ inactive -> "Enable"
+ end,
+ wxMenuItem:setText(Break#break.smi, Label),
+
+ TriggerMI = case Trigger of
+ enable -> Break#break.emi;
+ disable -> Break#break.dimi;
+ delete -> Break#break.demi
+ end,
+ wxMenuItem:check(TriggerMI).
+
+%%--------------------------------------------------------------------
+%% delete_break(Break)
+%% Break = #break{}
+%%--------------------------------------------------------------------
+delete_break(Break) ->
+ {Menu, MenuBtn} = Break#break.mb,
+ wxMenu:'Destroy'(Menu,MenuBtn).
+
+%%--------------------------------------------------------------------
+%% motion(X, Y) -> {X, Y}
+%% X = Y = integer()
+%%--------------------------------------------------------------------
+motion(X, Y) ->
+ receive
+ {gs, _Id, motion, _Data, [NX,NY]} ->
+ motion(NX, NY)
+ after 0 ->
+ {X, Y}
+ end.
+
+
+%%--------------------------------------------------------------------
+%% confirm(MonWin, String) -> ok | cancel
+%%--------------------------------------------------------------------
+
+confirm(Win,Message) ->
+ MD = wxMessageDialog:new(Win,to_string(Message),
+ [{style, ?wxOK bor ?wxCANCEL},
+ {caption, "Confirm"}]),
+ Res = case wxDialog:showModal(MD) of
+ ?wxID_OK -> ok;
+ _ -> cancel
+ end,
+ wxDialog:destroy(MD),
+ Res.
+
+%%--------------------------------------------------------------------
+%% notify(MonWin, String) -> ok
+%%--------------------------------------------------------------------
+
+notify(Win,Message) ->
+ MD = wxMessageDialog:new(Win,to_string(Message),
+ [{style, ?wxOK},
+ {caption, "Confirm"}]),
+ wxDialog:showModal(MD),
+ wxDialog:destroy(MD),
+ ok.
+
+%%--------------------------------------------------------------------
+%% entry(Parent, Title, Prompt, {Type, Value}) -> {Prompt, Val} | cancel
+%%--------------------------------------------------------------------
+
+entry(Parent, Title, Prompt, {Type, Value}) ->
+ Ted = wxTextEntryDialog:new(Parent, to_string(Prompt),
+ [{caption, to_string(Title)},
+ {value, to_string(Value)}]),
+
+ case wxDialog:showModal(Ted) of
+ ?wxID_OK ->
+ Res = case verify(Type, wxTextEntryDialog:getValue(Ted)) of
+ {edit,NewVal} ->
+ {Prompt,NewVal};
+ ignore ->
+ cancel
+ end,
+ wxTextEntryDialog:destroy(Ted),
+ Res;
+ _ ->
+ cancel
+ end.
+
+
+verify(Type, Str) ->
+ case erl_scan:string(Str) of
+ {ok, Tokens, _EndLine} when Type==term ->
+
+ case erl_parse:parse_term(Tokens++[{dot, 1}]) of
+ {ok, Value} -> {edit, Value};
+ _Error ->
+ ignore
+ end;
+ {ok, [{Type, _Line, Value}], _EndLine} when Type/=term ->
+ {edit, Value};
+ _Err ->
+ ignore
+ end.
+
+%%--------------------------------------------------------------------
+%% open_help/2
+%% opens browser with help file
+%%--------------------------------------------------------------------
+open_help(_Parent, HelpHtmlFile) ->
+ wx_misc:launchDefaultBrowser("file://" ++ HelpHtmlFile).
+
+%%--------------------------------------------------------------------
+%% to_string(Term) -> [integer()]
+%% to_string(Format,Args) -> [integer()]
+%%--------------------------------------------------------------------
+
+to_string(Atom) when is_atom(Atom) ->
+ atom_to_list(Atom);
+to_string(Integer) when is_integer(Integer) ->
+ integer_to_list(Integer);
+to_string([]) -> "";
+to_string(List) when is_list(List) ->
+ List;
+to_string(Term) ->
+ io_lib:format("~p",[Term]).
+
+to_string(Format,Args) ->
+ io_lib:format(Format, Args).
+
+menu_name(Atom, N) when is_atom(Atom) ->
+ menu_name(atom_to_list(Atom),N);
+menu_name(Str, Pos) when is_integer(Pos) ->
+ {S1,S2} = lists:split(Pos,Str),
+ S1 ++ [$&|S2];
+menu_name(Str,_) ->
+ Str.
+
+%%--------------------------------------------------------------------
+%% find_icon(File) -> Path or exists
+%%--------------------------------------------------------------------
+
+find_icon(File) ->
+ PrivDir = code:priv_dir(debugger),
+ PrivIcon = filename:append(PrivDir, File),
+ case filelib:is_regular(PrivIcon) of
+ true -> PrivIcon;
+ false ->
+ CurrDir = filename:dirname(code:which(?MODULE)),
+ CurrIcon = filename:append(CurrDir, File),
+ true = filelib:is_regular(CurrIcon),
+ CurrIcon
+ end.
+