From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/debugger/src/dbg_wx_win.erl | 332 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 lib/debugger/src/dbg_wx_win.erl (limited to 'lib/debugger/src/dbg_wx_win.erl') 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. + -- cgit v1.2.3