1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22-module(dbg_wx_break_win).
23
24%% External exports
25-export([create_win/5,
26	 update_functions/2,
27	 handle_event/2]).
28
29-include_lib("wx/include/wx.hrl").
30
31-record(winInfo, {type,            % line | conditional | function
32		  win,             % wxobj()
33		  entries,         % [{atom|integer, wxobj()}]
34		  trigger,         % [{wxobj(),enable | disable | delete}]
35		  listbox,         % wxobj()
36		  text,            % wxobj()
37		  ok,              % wxobj()
38		  funcs=[]         % [[Name, Arity]]
39		 }).
40
41%%====================================================================
42%% External exports
43%%====================================================================
44
45%%--------------------------------------------------------------------
46%% create_win(Win, Pos, Type, Mod, Line) -> #winInfo{}
47%%   Win = Top level window
48%%   Pos = {X, Y}
49%%     X = Y = integer()
50%%   Type =  line | conditional | function
51%%   Mod = atom() | ""
52%%   Line = integer() | ""
53%%--------------------------------------------------------------------
54
55create_win(Parent, Pos, function, Mod, _Line) ->
56    Win = wxDialog:new(Parent, ?wxID_ANY, "Function Break",
57		       [{pos, Pos},
58			{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}]),
59    MainS = wxBoxSizer:new(?wxVERTICAL),
60    Label = wxStaticText:new(Win, ?wxID_ANY, "Module:"),
61    Int = int:interpreted(),
62    IntStrs = [atom_to_list(M) || M <- Int],
63    Text  = wxComboBox:new(Win, ?wxID_ANY,
64			   [{value, dbg_wx_win:to_string(Mod)},
65			    {choices, IntStrs}]),
66
67    Expand = [{border, 5}, {flag,?wxLEFT bor ?wxRIGHT bor ?wxEXPAND}],
68    _ = wxSizer:add(MainS, Label, [{border,5},
69			       {flag,?wxTOP bor ?wxLEFT bor ?wxRIGHT}]),
70    _ = wxSizer:add(MainS, Text, Expand),
71    FunLabel = wxStaticText:new(Win, ?wxID_ANY, "Function:"),
72    LB = wxListBox:new(Win, ?wxID_ANY, [{size,{-1, 100}},{style,?wxLB_MULTIPLE}]),
73    _ = wxSizer:add(MainS, FunLabel, Expand),
74    _ = wxSizer:add(MainS, LB, [{proportion,1}|Expand]),
75    wxSizer:setMinSize(MainS, 300, 400),
76    OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL),
77    _ = wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
78    wxDialog:setSizer(Win,MainS),
79    _ = wxSizer:fit(MainS, Win),
80    wxSizer:setSizeHints(MainS,Win),
81    wxComboBox:setFocus(Text),
82    wxDialog:connect(Win,    command_button_clicked),
83    wxComboBox:connect(Text, command_text_updated),
84    wxListBox:connect(LB, command_listbox_selected),
85    wxListBox:connect(LB, command_listbox_doubleclicked),
86    OKId   = wxDialog:getAffirmativeId(Win),
87    OKButt = wxWindow:findWindowById(OKId, [{parent, Win}]),
88    wxWindow:disable(OKButt),
89    wxDialog:centreOnParent(Win),
90    wxDialog:show(Win),
91
92    #winInfo{type=function, win=Win, text=Text, ok=OKButt,
93	     entries=[], trigger=enable,
94	     listbox=LB, funcs=[]};
95
96create_win(Parent, Pos, Type, Mod, Line) ->
97    Title = case Type of
98		line -> "Line Break";
99		conditional -> "Conditional Break"
100	    end,
101    Style = ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER,
102    Win = wxDialog:new(Parent, ?wxID_ANY, Title,
103		       [{pos, Pos},
104			{style, Style}]),
105    %% Create Sizers
106    MainS = wxBoxSizer:new(?wxVERTICAL),
107
108    %% Add module
109    Int = int:interpreted(),
110    IntStrs = [atom_to_list(M) || M <- Int],
111    ModT  = wxComboBox:new(Win, ?wxID_ANY, [{choices,IntStrs}]),
112    ModSz = create_label_of_control(Win, "Module:", ModT, Mod),
113    _ = wxSizer:add(MainS,ModSz,[{flag, ?wxEXPAND}]),
114    %% Create rest of text input fields
115    Add = fun({IType, Label, Def}) ->
116		  {Sz, Text} = create_sizer_with_text(Win, Label, Def),
117		  _ = wxSizer:add(MainS, Sz, [{flag, ?wxEXPAND}]),
118		  {Text, IType}
119	  end,
120    Inputs = case Type of
121		 line ->
122		     [{integer,"Line:",Line}];
123		 conditional ->
124		     [{integer,"Line:",Line},
125		      {atom,"C-Module:",""},
126		      {atom,"C-Function:",""}]
127	     end,
128    %% Add the rest of the entries
129    Entries = wx:map(Add, Inputs),
130    %% Create and add radio box
131    {TriggerBox,Trigger} = create_trigger_box(Win),
132    _ = wxSizer:add(MainS, TriggerBox, [{border,5},{flag,?wxALL bor ?wxEXPAND}]),
133
134    _ = wxSizer:addStretchSpacer(MainS),
135    %% Put it together
136    OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL),
137    _ = wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]),
138    wxSizer:setMinSize(MainS, 300, -1),
139    wxDialog:setSizer(Win,MainS),
140    _ = wxSizer:fit(MainS, Win),
141    wxSizer:setSizeHints(MainS,Win),
142    wxComboBox:setFocus(ModT),
143    wxDialog:connect(Win, command_button_clicked),
144    wxDialog:connect(Win, command_text_updated),
145    OKId   = wxDialog:getAffirmativeId(Win),
146    OKButt = wxWindow:findWindowById(OKId),
147    wxWindow:disable(OKButt),
148    wxDialog:centreOnParent(Win),
149    wxDialog:show(Win),
150    #winInfo{type=Type, win=Win, text=ModT,
151	     entries=Entries, trigger=Trigger, ok=OKButt}.
152
153%%--------------------------------------------------------------------
154%% update_functions(WinInfo, Funcs) -> WinInfo
155%%   WinInfo = #winInfo{}
156%%   Funcs = [{Name, Arity}]
157%%     Name = atom()
158%%     Arity = integer()
159%%--------------------------------------------------------------------
160update_functions(WinInfo, Funcs) ->
161    Items = lists:map(fun([N, A]) ->
162			      lists:flatten(io_lib:format("~tw/~w", [N,A]))
163		      end,
164		      Funcs),
165    wxListBox:set(WinInfo#winInfo.listbox, Items),
166    WinInfo#winInfo{funcs=Funcs}.
167
168%%--------------------------------------------------------------------
169%% handle_event(WxEvent, WinInfo) -> Command
170%% WxEvent = #wx{}
171%% WinInfo = #winInfo{}
172%% Command = ignore
173%%         | stopped
174%%         | {win, WinInfo}
175%%         | {module, Mod}
176%%         | {break, [[Mod, Line]], Action}
177%%         | {break, [[Mod, Line, CMod, CFunc]], Action}
178%%         | {break, [[Mod, Func, Arity]], Action}
179%%--------------------------------------------------------------------
180handle_event(#wx{id=?wxID_CANCEL}, #winInfo{win=Win}) ->
181    wxDialog:destroy(Win),
182    stopped;
183handle_event(#wx{event=#wxCommand{type=command_text_updated}},
184	     #winInfo{type=function, text=Text, ok=OK}) ->
185    Module = wxComboBox:getValue(Text),
186    wxWindow:disable(OK),
187    {module, list_to_atom(Module)};
188handle_event(#wx{event=#wxCommand{type=command_text_updated}},
189	     #winInfo{text=Text, ok=OK, entries=Es}) ->
190    Module = wxComboBox:getValue(Text),
191    case check_input(Es) of
192	error -> wxWindow:disable(OK);
193	_Data when Module =/= "" -> wxWindow:enable(OK);
194	_ -> wxWindow:disable(OK)
195    end,
196    ignore;
197handle_event(#wx{event=#wxCommand{type=command_listbox_selected}},
198	     #winInfo{type=function, listbox=LB, ok=OK}) ->
199    case wxListBox:getSelections(LB) of
200	{N,_} when N > 0 -> wxWindow:enable(OK);
201	_ -> wxWindow:disable(OK)
202    end,
203    ignore;
204handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OKorDoubleClick}},
205	     #winInfo{type=function,win=Win,listbox=LB,funcs=Funcs,text=Text})
206  when OKorListBox =:= ?wxID_OK;
207       OKorDoubleClick =:= command_listbox_doubleclicked ->
208    Mod = wxComboBox:getValue(Text),
209    {_, IndexL} = wxListBox:getSelections(LB),
210    Breaks = [[list_to_atom(Mod)|lists:nth(Index+1, Funcs)] || Index <- IndexL],
211    wxDialog:destroy(Win),
212    {break, Breaks, enable};
213handle_event(#wx{id=?wxID_OK},#winInfo{win=Win,text=Text, entries=Es, trigger=Trigger}) ->
214    %% Non function box
215    Mod = wxComboBox:getValue(Text),
216    Data = check_input(Es),
217    Trigged = get_trigger(Trigger),
218    wxDialog:destroy(Win),
219    {break, [[list_to_atom(Mod)|Data]], Trigged};
220
221handle_event(_WxEvent, _WinInfo) ->
222    %% io:format("Ev: ~p ~n", [_WxEvent]),
223    ignore.
224
225check_input(Entries) ->
226    check_input(Entries, []).
227check_input([{Entry, Type} | Entries], Data) ->
228    Str = wxTextCtrl:getValue(Entry),
229    case erl_scan:string(Str) of
230	{ok, [{Type, _Line, Val}], _EndLine} ->
231	    check_input(Entries, [Val|Data]);
232	_Error -> error
233    end;
234check_input([], Data) -> lists:reverse(Data).
235
236create_sizer_with_text(Parent,Label,Def) ->
237    Text  = wxTextCtrl:new(Parent, ?wxID_ANY),
238    Sz = create_label_of_control(Parent, Label, Text, Def),
239    {Sz, Text}.
240
241create_label_of_control(Parent, Label, Control, Def) ->
242    Sizer = wxBoxSizer:new(?wxHORIZONTAL),
243    Text  = wxStaticText:new(Parent, ?wxID_ANY, Label),
244    Border = {border, 5},
245    Flag   = ?wxRIGHT bor ?wxLEFT bor ?wxALIGN_CENTRE_VERTICAL,
246    _ = wxSizer:add(Sizer, Text, [{proportion,1}, {flag,Flag}, Border]),
247    _ = wxSizer:add(Sizer, Control, [{proportion,3}, {flag,Flag bor ?wxEXPAND}, Border]),
248    wxControl:setLabel(Control, dbg_wx_win:to_string(Def)),
249    Sizer.
250
251create_trigger_box(Win) ->
252    SBox = wxStaticBox:new(Win, ?wxID_ANY, "Trigger Action:"),
253    SBS  = wxStaticBoxSizer:new(SBox, ?wxVERTICAL),
254    Ebtn = wxRadioButton:new(Win, ?wxID_ANY, "Enable"),
255    _ = wxSizer:add(SBS,Ebtn),
256    Dibtn = wxRadioButton:new(Win, ?wxID_ANY, "Disable"),
257    _ = wxSizer:add(SBS,Dibtn),
258    Debtn = wxRadioButton:new(Win, ?wxID_ANY, "Delete"),
259    _ = wxSizer:add(SBS,Debtn),
260    wxRadioButton:setValue(Ebtn, true),
261    {SBS, [{Ebtn,enable},{Dibtn,disable},{Debtn,delete}]}.
262
263get_trigger([{Btn,Op}|R]) ->
264    case wxRadioButton:getValue(Btn) of
265	true -> Op;
266	false -> get_trigger(R)
267    end.
268
269
270