%%
%% %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_break_win).
%% External exports
-export([create_win/5,
update_functions/2,
handle_event/2]).
-include_lib("wx/include/wx.hrl").
-record(winInfo, {type, % line | conditional | function
win, % wxobj()
entries, % [{atom|integer, wxobj()}]
trigger, % [{wxobj(),enable | disable | delete}]
listbox, % wxobj()
text, % wxobj()
ok, % wxobj()
funcs=[] % [[Name, Arity]]
}).
%%====================================================================
%% External exports
%%====================================================================
%%--------------------------------------------------------------------
%% create_win(Win, Pos, Type, Mod, Line) -> #winInfo{}
%% Win = Top level window
%% Pos = {X, Y}
%% X = Y = integer()
%% Type = line | conditional | function
%% Mod = atom() | ""
%% Line = integer() | ""
%%--------------------------------------------------------------------
create_win(Parent, Pos, function, Mod, _Line) ->
Win = wxDialog:new(Parent, ?wxID_ANY, "Function Break",
[{pos, Pos},
{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}]),
MainS = wxBoxSizer:new(?wxVERTICAL),
Label = wxStaticText:new(Win, ?wxID_ANY, "Module:"),
Int = int:interpreted(),
IntStrs = [atom_to_list(M) || M <- Int],
Text = wxComboBox:new(Win, ?wxID_ANY,
[{value, dbg_wx_win:to_string(Mod)},
{choices, IntStrs}]),
Expand = [{border, 5}, {flag,?wxLEFT bor ?wxRIGHT bor ?wxEXPAND}],
wxSizer:add(MainS, Label, [{border,5},
{flag,?wxTOP bor ?wxLEFT bor ?wxRIGHT}]),
wxSizer:add(MainS, Text, Expand),
FunLabel = wxStaticText:new(Win, ?wxID_ANY, "Function:"),
LB = wxListBox:new(Win, ?wxID_ANY, [{size,{-1, 100}},{style,?wxLB_MULTIPLE}]),
wxSizer:add(MainS, FunLabel, Expand),
wxSizer:add(MainS, LB, [{proportion,1}|Expand]),
wxSizer:setMinSize(MainS, 300, 400),
OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL),
wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
wxDialog:setSizer(Win,MainS),
wxSizer:fit(MainS, Win),
wxSizer:setSizeHints(MainS,Win),
wxComboBox:setFocus(Text),
wxDialog:connect(Win, command_button_clicked),
wxComboBox:connect(Text, command_text_updated),
wxListBox:connect(LB, command_listbox_selected),
wxListBox:connect(LB, command_listbox_doubleclicked),
OkId = wxDialog:getAffirmativeId(Win),
OKButt = wxWindow:findWindowById(OkId, [{parent, Win}]),
wxWindow:disable(OKButt),
wxDialog:centreOnParent(Win),
wxDialog:show(Win),
#winInfo{type=function, win=Win, text=Text, ok=OKButt,
entries=[], trigger=enable,
listbox=LB, funcs=[]};
create_win(Parent, Pos, Type, Mod, Line) ->
Title = case Type of
line -> "Line Break";
conditional -> "Conditional Break"
end,
Style = ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER,
Win = wxDialog:new(Parent, ?wxID_ANY, Title,
[{pos, Pos},
{style, Style}]),
%% Create Sizers
MainS = wxBoxSizer:new(?wxVERTICAL),
%% Add module
Int = int:interpreted(),
IntStrs = [atom_to_list(M) || M <- Int],
ModT = wxComboBox:new(Win, ?wxID_ANY, [{choices,IntStrs}]),
ModSz = create_label_of_control(Win, "Module:", ModT, Mod),
wxSizer:add(MainS,ModSz,[{flag, ?wxEXPAND}]),
%% Create rest of text input fields
Add = fun({IType, Label, Def}) ->
{Sz, Text} = create_sizer_with_text(Win, Label, Def),
wxSizer:add(MainS, Sz, [{flag, ?wxEXPAND}]),
{Text, IType}
end,
Inputs = case Type of
line ->
[{integer,"Line:",Line}];
conditional ->
[{integer,"Line:",Line},
{atom,"C-Module:",""},
{atom,"C-Function:",""}]
end,
%% Add the rest of the entries
Entries = wx:map(Add, Inputs),
%% Create and add radio box
{TriggerBox,Trigger} = create_trigger_box(Win),
wxSizer:add(MainS, TriggerBox, [{border,5},{flag,?wxALL bor ?wxEXPAND}]),
wxSizer:addStretchSpacer(MainS),
%% Put it together
OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL),
wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
wxSizer:setMinSize(MainS, 300, -1),
wxDialog:setSizer(Win,MainS),
wxSizer:fit(MainS, Win),
wxSizer:setSizeHints(MainS,Win),
wxComboBox:setFocus(ModT),
wxDialog:connect(Win, command_button_clicked),
wxDialog:connect(Win, command_text_updated),
OkId = wxDialog:getAffirmativeId(Win),
OKButt = wxWindow:findWindowById(OkId),
wxWindow:disable(OKButt),
wxDialog:centreOnParent(Win),
wxDialog:show(Win),
#winInfo{type=Type, win=Win, text=ModT,
entries=Entries, trigger=Trigger, ok=OKButt}.
%%--------------------------------------------------------------------
%% update_functions(WinInfo, Funcs) -> WinInfo
%% WinInfo = #winInfo{}
%% Funcs = [{Name, Arity}]
%% Name = atom()
%% Arity = integer()
%%--------------------------------------------------------------------
update_functions(WinInfo, Funcs) ->
Items = lists:map(fun([N, A]) ->
lists:flatten(io_lib:format("~p/~p", [N,A]))
end,
Funcs),
wxListBox:set(WinInfo#winInfo.listbox, Items),
WinInfo#winInfo{funcs=Funcs}.
%%--------------------------------------------------------------------
%% handle_event(WxEvent, WinInfo) -> Command
%% WxEvent = #wx{}
%% 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(#wx{id=?wxID_CANCEL}, #winInfo{win=Win}) ->
wxDialog:destroy(Win),
stopped;
handle_event(#wx{event=#wxCommand{type=command_text_updated}},
#winInfo{type=function, text=Text, ok=Ok}) ->
Module = wxComboBox:getValue(Text),
wxWindow:disable(Ok),
{module, list_to_atom(Module)};
handle_event(#wx{event=#wxCommand{type=command_text_updated}},
#winInfo{text=Text, ok=Ok, entries=Es}) ->
Module = wxComboBox:getValue(Text),
case check_input(Es) of
error -> wxWindow:disable(Ok);
_Data when Module =/= "" -> wxWindow:enable(Ok);
_ -> wxWindow:disable(Ok)
end,
ignore;
handle_event(#wx{event=#wxCommand{type=command_listbox_selected}},
#winInfo{type=function, listbox=LB, ok=Ok}) ->
case wxListBox:getSelections(LB) of
{N,_} when N > 0 -> wxWindow:enable(Ok);
_ -> wxWindow:disable(Ok)
end,
ignore;
handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OkorDoubleClick}},
#winInfo{type=function,win=Win,listbox=LB,funcs=Funcs,text=Text})
when OKorListBox =:= ?wxID_OK;
OkorDoubleClick =:= command_listbox_doubleclicked ->
Mod = wxComboBox:getValue(Text),
{_, IndexL} = wxListBox:getSelections(LB),
Breaks = [[list_to_atom(Mod)|lists:nth(Index+1, Funcs)] || Index <- IndexL],
wxDialog:destroy(Win),
{break, Breaks, enable};
handle_event(#wx{id=?wxID_OK},#winInfo{win=Win,text=Text, entries=Es, trigger=Trigger}) ->
%% Non function box
Mod = wxComboBox:getValue(Text),
Data = check_input(Es),
Trigged = get_trigger(Trigger),
wxDialog:destroy(Win),
{break, [[list_to_atom(Mod)|Data]], Trigged};
handle_event(_WxEvent, _WinInfo) ->
%% io:format("Ev: ~p ~n", [_WxEvent]),
ignore.
check_input(Entries) ->
check_input(Entries, []).
check_input([{Entry, Type} | Entries], Data) ->
Str = wxTextCtrl:getValue(Entry),
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).
create_sizer_with_text(Parent,Label,Def) ->
Text = wxTextCtrl:new(Parent, ?wxID_ANY),
Sz = create_label_of_control(Parent, Label, Text, Def),
{Sz, Text}.
create_label_of_control(Parent, Label, Control, Def) ->
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
Text = wxStaticText:new(Parent, ?wxID_ANY, Label),
Border = {border, 5},
Flag = ?wxRIGHT bor ?wxLEFT bor ?wxALIGN_CENTRE_VERTICAL,
wxSizer:add(Sizer, Text, [{proportion,1}, {flag,Flag}, Border]),
wxSizer:add(Sizer, Control, [{proportion,3}, {flag,Flag bor ?wxEXPAND}, Border]),
wxControl:setLabel(Control, dbg_wx_win:to_string(Def)),
Sizer.
create_trigger_box(Win) ->
SBox = wxStaticBox:new(Win, ?wxID_ANY, "Trigger Action:"),
SBS = wxStaticBoxSizer:new(SBox, ?wxVERTICAL),
Ebtn = wxRadioButton:new(Win, ?wxID_ANY, "Enable"),
wxSizer:add(SBS,Ebtn),
Dibtn = wxRadioButton:new(Win, ?wxID_ANY, "Disable"),
wxSizer:add(SBS,Dibtn),
Debtn = wxRadioButton:new(Win, ?wxID_ANY, "Delete"),
wxSizer:add(SBS,Debtn),
wxRadioButton:setValue(Ebtn, true),
{SBS, [{Ebtn,enable},{Dibtn,disable},{Debtn,delete}]}.
get_trigger([{Btn,Op}|R]) ->
case wxRadioButton:getValue(Btn) of
true -> Op;
false -> get_trigger(R)
end.