%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1997-2012. 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(tv_pb).
-compile([{nowarn_deprecated_function,{gs,config,2}},
{nowarn_deprecated_function,{gs,destroy,1}},
{nowarn_deprecated_function,{gs,frame,2}}]).
-export([pb/1]).
-include("tv_int_def.hrl").
-include("tv_pd_int_msg.hrl").
-include("tv_pb_int_def.hrl").
%%%*********************************************************************
%%% EXTERNAL FUNCTIONS
%%%*********************************************************************
%%======================================================================
%% Function: pb.
%%
%% Return Value: None.
%%
%% Description: Process controlling the grid buttons on the display.
%%
%% Parameters: None.
%%======================================================================
pb(ParentPid) ->
process_flag(trap_exit, true),
ProcVars = #process_variables{parent_pid = ParentPid},
loop(ProcVars).
%%%********************************************************************
%%% INTERNAL FUNCTIONS
%%%********************************************************************
%%======================================================================
%% Function: loop.
%%
%% Return Value: None.
%%
%% Description: Eternal (well, almost) loop, receiving messages and
%% handling them.
%%
%% Parameters:
%%======================================================================
loop(ProcVars) ->
receive
Msg ->
case Msg of
#pb_update_vbtns{} ->
NewProcVars = update_vbtns(Msg, ProcVars),
loop(NewProcVars);
#pb_key_info{} ->
NewProcVars = update_keys(Msg, ProcVars),
loop(NewProcVars);
#pb_update_hbtns{} ->
NewProcVars = update_hbtns(Msg, ProcVars),
loop(NewProcVars);
#pb_set_sort_col{} ->
NewProcVars = set_sort_col(Msg, ProcVars),
loop(NewProcVars);
#pb_remove_marks{} ->
NewProcVars = remove_marks(ProcVars),
loop(NewProcVars);
#pb_init_btns{} ->
NewProcVars = init_btns(Msg, ProcVars),
loop(NewProcVars);
{gs, Id, Event, Data, Args} ->
NewProcVars = gs_messages({Id, Event, Data, Args}, ProcVars),
loop(NewProcVars);
{'EXIT', Pid, Reason} ->
ParentPid = ProcVars#process_variables.parent_pid,
exit_signals({Pid, Reason}, ParentPid, ProcVars),
loop(ProcVars);
_Other ->
loop(ProcVars)
end
end.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
exit_signals(ExitInfo, ParentPid, _ProcVars) ->
case ExitInfo of
{ParentPid, _Reason} ->
exit(normal);
_Other ->
done
end.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
gs_messages(Msg, ProcVars) ->
case Msg of
{Id, click, {hbtn, RealCol, VirtualCol}, _Args} ->
handle_col_marking(Id, RealCol, VirtualCol, ProcVars);
{Id, buttonpress, {resbtn, RealCol, VirtualCol, Xpos}, [1 | _Tail]} ->
handle_col_resizing(Id, RealCol, VirtualCol, Xpos, ProcVars),
ProcVars;
{_Id, click, {vbtn, RealRow, VirtualRow}, _Args} ->
handle_row_marking(RealRow, VirtualRow, ProcVars);
_OtherMessage ->
ProcVars
end.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
remove_marks(ProcVars) ->
#process_variables{col_mark_params = ColMarkP,
row_mark_params = RowMarkP} = ProcVars,
#col_mark_params{col_btn_id = BtnId,
virtual_col_marked = VirtualCol,
virtual_sort_col = SortCol} = ColMarkP,
case BtnId of
undefined ->
done;
_AnyId ->
case VirtualCol of
SortCol ->
gs:config(BtnId, [{bg, ?SORT_MARK_COLOR},
{fg, {0, 0, 0}}
]);
_Other ->
gs:config(BtnId, [{bg, ?DEFAULT_BG_COLOR},
{fg, {0, 0, 0}}
])
end
end,
NewRowMarkP = RowMarkP#row_mark_params{virtual_row_marked = undefined,
real_row_marked = undefined
},
NewColMarkP = ColMarkP#col_mark_params{col_btn_id = undefined,
virtual_col_marked = undefined
},
ProcVars#process_variables{col_mark_params = NewColMarkP,
row_mark_params = NewRowMarkP
}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
handle_col_marking(BtnId, RealCol, VirtualCol, ProcVars) ->
#process_variables{parent_pid = PdPid,
col_mark_params = ColMarkP,
row_mark_params = RowMarkP} = ProcVars,
#col_mark_params{col_btn_id = OldBtnId,
virtual_col_marked = OldVirtualCol,
virtual_sort_col = SortCol} = ColMarkP,
{ColMarked, NewColMarkP} = mark_col_btn(BtnId, OldBtnId, VirtualCol,
OldVirtualCol, RealCol, SortCol,
ColMarkP),
PdPid ! #pb_col_marked{sender = self(),
col_marked = ColMarked,
real_col = RealCol,
virtual_col = VirtualCol
},
NewRowMarkP = RowMarkP#row_mark_params{virtual_row_marked = undefined,
real_row_marked = undefined
},
ProcVars#process_variables{col_mark_params = NewColMarkP,
row_mark_params = NewRowMarkP
}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
handle_row_marking(RealRow, VirtualRow, ProcVars) ->
#process_variables{parent_pid = PdPid,
col_mark_params = ColMarkP,
row_mark_params = RowMarkP} = ProcVars,
#col_mark_params{col_btn_id = OldBtnId,
virtual_col_marked = OldVirtualCol,
virtual_sort_col = SortCol} = ColMarkP,
{_ColMarked, NewColMarkP} = mark_col_btn(OldBtnId, OldBtnId, OldVirtualCol,
OldVirtualCol, undefined, SortCol,
ColMarkP),
#row_mark_params{virtual_row_marked = OldVirtualRow} = RowMarkP,
% Check if row shall be marked or unmarked!
{RowMarked, NewRowMarkP} = check_marked_row(VirtualRow, OldVirtualRow, RealRow,
RowMarkP),
PdPid ! #pb_row_marked{sender = self(),
row_marked = RowMarked,
real_row = RealRow,
virtual_row = VirtualRow
},
ProcVars#process_variables{row_mark_params = NewRowMarkP,
col_mark_params = NewColMarkP}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
%% Three cases: no button previously clicked, or same button clicked,
%% or some other button clicked.
check_marked_row(NewVirtRow, undefined, RealRow, RowMarkP) ->
% No btn already pressed!
{true, RowMarkP#row_mark_params{virtual_row_marked = NewVirtRow,
real_row_marked = RealRow}};
check_marked_row(NewVirtRow, OldVirtRow, _RealRow, RowMarkP) when NewVirtRow =:= OldVirtRow ->
% The button previously pressed has been pressed again!
{false, RowMarkP#row_mark_params{virtual_row_marked = undefined,
real_row_marked = undefined}};
check_marked_row(NewVirtRow, _OldVirtRow, RealRow, RowMarkP) ->
% A new btn has been pressed!
{true, RowMarkP#row_mark_params{virtual_row_marked = NewVirtRow,
real_row_marked = RealRow}}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
set_sort_col(Msg, ProcVars) ->
#pb_set_sort_col{virtual_col = SortCol} = Msg,
tv_pb_funcs:set_new_sort_col(SortCol, ProcVars).
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
%% Three cases: no button previously clicked, or same button clicked,
%% or some other button clicked.
mark_col_btn(NewId, undefined, NewVirtCol, _OldVirtCol, _RealCol, _SortCol, ColMarkP) ->
% No btn already pressed!
gs:config(NewId, [{bg, ?COL_MARK_COLOR},
{fg, {255, 255, 255}}
]),
{true, ColMarkP#col_mark_params{col_btn_id = NewId,
virtual_col_marked = NewVirtCol}};
mark_col_btn(NewId, _OldId, NewVirtCol, OldVirtCol, _RealCol, SortCol, ColMarkP) when NewVirtCol =:= OldVirtCol, NewVirtCol =:= SortCol ->
% The button previously pressed has been pressed again!
gs:config(NewId, [{bg, ?SORT_MARK_COLOR},
{fg, {0, 0, 0}}
]),
{false, ColMarkP#col_mark_params{col_btn_id = undefined,
virtual_col_marked = undefined}};
mark_col_btn(NewId, _OldId, NewVirtCol, OldVirtCol, _RealCol, _SortCol, ColMarkP) when NewVirtCol =:= OldVirtCol ->
% The button previously pressed has been pressed again!
gs:config(NewId, [{bg, ?DEFAULT_BG_COLOR},
{fg, {0, 0, 0}}
]),
{false, ColMarkP#col_mark_params{col_btn_id = undefined,
virtual_col_marked = undefined}};
mark_col_btn(NewId, OldId, NewVirtCol, _OldVirtCol, _RealCol, _SortCol, ColMarkP) ->
% A new btn has been pressed!
gs:config(OldId, [{bg, ?DEFAULT_BG_COLOR},
{fg, {0, 0, 0}}
]),
gs:config(NewId, [{bg, ?COL_MARK_COLOR},
{fg, {255, 255, 255}}
]),
{true, ColMarkP#col_mark_params{col_btn_id = NewId,
virtual_col_marked = NewVirtCol}}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
handle_col_resizing(RbtnId, RealCol, VirtualCol, Xpos, ProcVars) ->
gs:config(RbtnId, [{motion, true}]),
#process_variables{parent_pid = ParentPid,
grid_frame_id = GrFrId,
grid_frame_height = Height,
hbtn_height = HbtnH,
resbtn_width = RbtnW,
cols_shown = ColsShown} = ProcVars,
LineId = gs:frame(GrFrId, [{width, 1},
{height, Height - HbtnH},
{x, Xpos},
{y, HbtnH - 1},
{bg, ?DEFAULT_BG_COLOR}
]),
MinColWidth = RbtnW,
OldColWidth = lists:nth(RealCol, ColsShown),
Xdiff = get_xdiff(RbtnId, 1, 0, LineId, Xpos, MinColWidth - OldColWidth),
ParentPid ! #pb_new_colwidth{sender = self(),
real_col = RealCol,
virtual_col = VirtualCol,
xdiff = Xdiff},
gs:config(RbtnId, [{motion, false}]),
gs:destroy(LineId).
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
get_xdiff(Id, Btn, LastXdiff, LineId, LineXpos, MinAllowedXdiff) ->
receive
{gs, Id, motion, {resbtn, _RealCol, _VirtCol, _OldXpos}, [NewXdiff | _T]} ->
UsedXdiff = erlang:max(MinAllowedXdiff, NewXdiff),
gs:config(LineId, [{x, LineXpos + UsedXdiff}]),
get_xdiff(Id, Btn, UsedXdiff, LineId, LineXpos, MinAllowedXdiff);
{gs, Id, buttonrelease, _Data, [Btn | _T]} ->
LastXdiff;
{gs, Id, buttonrelease, _Data, _Args} ->
get_xdiff(Id, Btn, LastXdiff, LineId, LineXpos, MinAllowedXdiff);
{gs, Id, buttonpress, _Data, _Args} ->
get_xdiff(Id, Btn, LastXdiff, LineId, LineXpos, MinAllowedXdiff)
end.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
init_btns(Msg, ProcVars) ->
#pb_init_btns{parent_id = ParentId,
parent_width = Width,
parent_height = Height,
ypos = Ypos,
hbtn_height = HbtnH,
resbtn_width = RbtnW,
vbtn_width = VbtnW,
nof_rows = NofRows,
row_height = RowHeight,
first_col_shown = FirstColShown,
cols_shown = ColsShown} = Msg,
NewProcVars = tv_pb_funcs:init_btns(ParentId, Ypos, HbtnH, VbtnW, RbtnW,
FirstColShown, ColsShown, NofRows,
RowHeight, ProcVars),
gs:frame(ParentId, [{bg, {0, 0, 0}},
{bw, 0},
{width, 1300},
{height, 1},
{x, 0},
{y, Ypos - 1}
]),
NewProcVars#process_variables{grid_frame_width = Width,
grid_frame_height = Height
}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
update_hbtns(Msg, ProcVars) ->
#pb_update_hbtns{parent_width = Width,
parent_height = Height,
first_col_shown = FirstColShown,
cols_shown = ColsShown} = Msg,
NewProcVars = tv_pb_funcs:update_hbtns(FirstColShown, ColsShown, ProcVars),
NewProcVars#process_variables{grid_frame_width = Width,
grid_frame_height = Height
}.
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
update_vbtns(Msg, ProcVars) ->
#pb_update_vbtns{color_list = Colors,
first_row_shown = FirstRowShown,
nof_rows_shown = NofRowsShown,
blinking_enabled = BlinkEnabled} = Msg,
tv_pb_funcs:update_vbtns(NofRowsShown, FirstRowShown, Colors, BlinkEnabled,
ProcVars).
%%======================================================================
%% Function:
%%
%% Return Value:
%%
%% Description:
%%
%% Parameters:
%%======================================================================
update_keys(Msg, ProcVars) ->
#pb_key_info{list_of_keys = KeyList} = Msg,
tv_pb_funcs:update_keys(KeyList, ProcVars).