aboutsummaryrefslogtreecommitdiffstats
path: root/lib/gs/src/gstk_window.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/gs/src/gstk_window.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/gs/src/gstk_window.erl')
-rw-r--r--lib/gs/src/gstk_window.erl369
1 files changed, 369 insertions, 0 deletions
diff --git a/lib/gs/src/gstk_window.erl b/lib/gs/src/gstk_window.erl
new file mode 100644
index 0000000000..acac452ed1
--- /dev/null
+++ b/lib/gs/src/gstk_window.erl
@@ -0,0 +1,369 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-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%
+%%
+
+%%
+%% ------------------------------------------------------------
+%% Basic Window Type.
+%% ------------------------------------------------------------
+
+-module(gstk_window).
+
+%%------------------------------------------------------------------------------
+%% WINDOW OPTIONS
+%%
+%% Attributes:
+%% x Int
+%% y Int
+%% width Int
+%% height Int
+%% bg Color
+%% bw Int
+%% relief Relief [flat|raised|sunken|ridge|groove]
+%% highlightbw Int
+%% highlightbg Color
+%% highlightfg Color
+%% map Bool
+%% iconify Bool
+%% title String
+%% iconname String
+%% iconbitmap Bitmap
+%% iconmask Bitmap
+%% data Data
+%% cursor arrow|busy|cross|hand|help|resize|text
+%%
+%% Commands:
+%% raise
+%% lower
+%% setfocus Bool
+%%
+%% Events:
+%% configure [Bool | {Bool, Data}]
+%% enter [Bool | {Bool, Data}]
+%% leave [Bool | {Bool, Data}]
+%% motion [Bool | {Bool, Data}]
+%% keypress [Bool | {Bool, Data}]
+%% keyrelease [Bool | {Bool, Data}]
+%% buttonpress [Bool | {Bool, Data}]
+%% buttonrelease [Bool | {Bool, Data}]
+%% focus [Bool | {Bool, Data}]
+%% destroy [Bool | {Bool, Data}]
+%%
+%% Read options:
+%% children
+%% id
+%% parent
+%% type
+%%
+%% Not Implemented:
+%% screen ?????????
+%% map
+%% unmap
+%% iconify
+%% deiconify
+%% focusmodel [active|passive] (wm focusmodel)
+%%
+
+-export([create/3, config/3, read/3, delete/2, event/5,destroy_win/1]).
+-export([option/5,read_option/5,mk_create_opts_for_child/4]).
+
+-include("gstk.hrl").
+% bind . <1> {puts "x: [expr %X - [winfo rootx .]] y: [expr %Y - [wi rooty .]]"}
+
+%%-----------------------------------------------------------------------------
+%% MANDATORY INTERFACE FUNCTIONS
+%%-----------------------------------------------------------------------------
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : create/3
+%% Purpose : Create a widget of the type defined in this module.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+create(DB, Gstkid, Opts) ->
+ TkW = gstk_generic:mk_tkw_child(DB,Gstkid),
+ NGstkid=Gstkid#gstkid{widget=TkW},
+ case gstk_generic:make_command(transform_geometry_opts(Opts),
+ NGstkid, TkW, "", ";", DB) of
+ {error,Reason} -> {error,Reason};
+ Cmd when is_list(Cmd) ->
+ BindCmd = gstk_generic:bind(DB, Gstkid, TkW, configure, true),
+% io:format("\nWINDOW1: ~p\n",[TkW]),
+% io:format("\nWINDOW1: ~p\n",[Cmd]),
+% io:format("\nWINDOW1: ~p\n",[BindCmd]),
+ gstk:exec(["toplevel ", TkW,Cmd,$;,BindCmd]),
+ NGstkid
+ end.
+
+mk_create_opts_for_child(DB,Cgstkid, Pgstkid, Opts) ->
+ gstk_generic:mk_create_opts_for_child(DB,Cgstkid,Pgstkid,Opts).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : config/3
+%% Purpose : Configure a widget of the type defined in this module.
+%% Args : DB - The Database
+%% Gstkid - The gstkid of the widget
+%% Opts - A list of options for configuring the widget
+%%
+%% Return : [true | {bad_result, Reason}]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+config(DB, Gstkid, Opts) ->
+ TkW = Gstkid#gstkid.widget,
+ SimplePreCmd = [TkW, " conf"],
+ gstk_generic:mk_cmd_and_exec(transform_geometry_opts(Opts),
+ Gstkid,TkW,SimplePreCmd,"",DB).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : read/3
+%% Purpose : Read one option from a widget
+%% Args : DB - The Database
+%% Gstkid - The gstkid of the widget
+%% Opt - An option to read
+%%
+%% Return : [OptionValue | {bad_result, Reason}]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+read(DB, Gstkid, Opt) ->
+ gstk_generic:read_option(DB, Gstkid, Opt).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : delete/2
+%% Purpose : Delete widget from databas and return tkwidget to destroy
+%% Args : DB - The Database
+%% Gstkid - The gstkid of the widget
+%%
+%% Return : TkWidget to destroy
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+delete(DB, Gstkid) ->
+ gstk_db:delete_widget(DB, Gstkid),
+ Gstkid#gstkid.widget.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : event/5
+%% Purpose : Construct the event and send it to the owner of the widget
+%% Args : DB - The Database
+%% Gstkid - The gstkid of the widget
+%% Etype - The event type
+%% Edata - The event data
+%% Args - The data from tcl/tk
+%%
+%% Return : [true | {bad_result, Reason}]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+event(DB, Gstkid, configure, Edata, Args) ->
+ [W,H|_] = Args,
+ gstk_db:insert_opt(DB,Gstkid,{width,W}),
+ gstk_db:insert_opt(DB,Gstkid,{height,H}),
+ case gstk_db:opt(DB,Gstkid,configure) of
+ true ->
+ apply(gstk_generic,event,[DB,Gstkid,configure,Edata,Args]);
+ false ->
+ ok
+ end;
+event(DB, Gstkid, destroy, Edata, Args) ->
+ spawn(gstk_window,destroy_win,[gstk:make_extern_id(Gstkid#gstkid.id,DB)]),
+ gstk_generic:event(DB, Gstkid, destroy, Edata, Args);
+event(DB, Gstkid, Etype, Edata, Args) ->
+ gstk_generic:event(DB, Gstkid, Etype, Edata, Args).
+
+destroy_win(ID) ->
+ gs:destroy(ID).
+%%------------------------------------------------------------------------------
+%% MANDATORY FUNCTIONS
+%%------------------------------------------------------------------------------
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : option/4
+%% Purpose : Take care of options
+%% Args : Option - An option tuple
+%% Gstkid - The gstkid of the widget
+%% TkW - The tk-widget
+%% DB - The Database
+%%
+%% Return : A tuple {OptionType, OptionCmd}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%-define(REGEXP,"regexp {(\\d+)x(\\d+)\\+?(-?\\d+)\\+?(-?\\d+)} ").
+% FIXME: Is this ok? Always positive?
+-define(REGEXP,"regexp {(\\d+)x(\\d+)\\+(\\d+)\\+(\\d+)} ").
+
+option(Option, Gstkid, TkW, DB,_) ->
+ case Option of
+%% Bug in tcl/tk complicates setting of a single x,y,width,height.
+ {x, X} ->
+ {c,
+ [?REGEXP,"[wm ge ",TkW, "] g w h x y;wm ge ", TkW,
+ " ${w}x$h",signed(X),"+$y;update idletasks"]};
+ {y, Y} ->
+ {c,[?REGEXP,"[wm ge ",TkW, "] g w h x y;wm ge ", TkW,
+ " ${w}x$h+$x",signed(Y),"; update idletasks"]};
+ {width, Width} when Width >= 0 -> % FIXME: Needed test?
+ case gstk_db:opt_or_not(DB,Gstkid,width) of
+ {value,Width} -> none;
+ _Q ->
+ gstk_db:insert_opt(DB,Gstkid,{width,Width}),
+ {c,[?REGEXP,"[wm ge ",TkW, "] g w h x y;wm ge ", TkW," ",
+ gstk:to_ascii(Width),"x$h+$x+$y;update idletasks"]}
+ end;
+ {height, Height} when Height >= 0 -> % FIXME: Needed test?
+ case gstk_db:opt_or_not(DB,Gstkid,height) of
+ {value,Height} -> none;
+ _Q -> % FIXME: Why different?
+ gstk_db:insert_opt(DB,Gstkid,{height,Height}),
+ {c,
+ ["wm ge ",TkW,
+ " [winfo w ", TkW, "]x",gstk:to_ascii(Height),
+ ";update idletasks"]}
+ end;
+ {width_height, {W,H}} when W >= 0, H >= 0 ->
+ case {gstk_db:opt_or_not(DB,Gstkid,width),
+ gstk_db:opt_or_not(DB,Gstkid,height)} of
+ {{value,W},{value,H}} ->
+ none;
+ _OtherSize ->
+ gstk_db:insert_opt(DB,Gstkid,{height,H}),
+ gstk_db:insert_opt(DB,Gstkid,{width,W}),
+ {c, ["update idletasks;wm ge ", TkW, " ",
+ gstk:to_ascii(W),"x",gstk:to_ascii(H),
+ ";update idletasks"]}
+ end;
+ {xy, {X,Y}} ->
+ {c, [?REGEXP,"[wm ge ",TkW, "] g w h x y;wm ge ", TkW,
+ " ${w}x$h", signed(X),signed(Y),
+ ";update idletasks"]};
+ {bg, Color} -> {s, [" -bg ", gstk:to_color(Color)]};
+ {map, true} -> {c, ["wm deiconify ", TkW]};
+ {map, false} -> {c, ["wm withdraw ", TkW]};
+ {configure, On} ->
+ gstk_db:insert_opt(DB,Gstkid,{configure,On}),
+ none;
+ {iconify, true} -> {c, ["wm iconify ", TkW]};
+ {iconify, false} -> {c, ["wm deiconify ", TkW]};
+ {title, Title} -> {c, ["wm title ", TkW, " " ,
+ gstk:to_ascii(Title)]};
+ {iconname, Name} -> {c, ["wm iconn ",TkW, " ",
+ gstk:to_ascii(Name)]};
+ {iconbitmap, Bitmap} -> {c, ["wm iconb ",TkW, " ",
+ gstk:to_ascii(Bitmap)]};
+ {iconmask, Bitmap} -> {c, ["wm iconm ",TkW, " ",
+ gstk:to_ascii(Bitmap)]};
+ raise -> {c, ["raise ", TkW]};
+ lower -> {c, ["lower ", TkW]};
+ {setfocus, true} -> {c, ["focus ", TkW]};
+ {setfocus, false} -> {c, ["focus {}"]};
+ {buttonpress, On} ->
+ Eref = mk_eref(On, DB, Gstkid, buttonpress),
+ {c,["bind ",TkW," <ButtonPress> ",
+ event_onoff(["{erlsend ",Eref," %b ",xy_abs_str(TkW),"};"],On)]};
+ {buttonrelease, On} ->
+ Eref = mk_eref(On, DB, Gstkid, buttonrelease),
+ {c,["bind ",TkW," <ButtonRelease> ",
+ event_onoff(["{erlsend ",Eref," %b ",xy_abs_str(TkW),"};"],On)]};
+ {motion, On} ->
+ Eref = mk_eref(On, DB, Gstkid, motion),
+ {c,["bind ",TkW," <Motion> ",
+ event_onoff(["{erlsend ",Eref," ",xy_abs_str(TkW),"};"],On)]};
+ _ -> invalid_option
+ end.
+
+xy_abs_str(TkW) ->
+ ["[expr %X-[winfo rootx ",TkW,"]] [expr %Y-[winfo rooty ",TkW,"]]"].
+
+event_onoff(Str, true) -> Str;
+event_onoff(_,false) -> "{}".
+
+mk_eref(false, DB, Gstkid, Etype) ->
+ gstk_db:delete_event(DB, Gstkid, Etype),
+ dummy;
+mk_eref(true,DB,Gstkid,Etype) ->
+ gstk_db:insert_event(DB, Gstkid, Etype, []).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Function : read_option/3
+%% Purpose : Take care of a read option
+%% Args : DB - The Database
+%% Gstkid - The gstkid of the widget
+%% Option - An option
+%%
+%% Return : The value of the option or invalid_option
+%% [OptionValue | {bad_result, Reason}]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+read_option(Option, Gstkid, TkW, DB,_) ->
+ case Option of
+ x -> tcl2erl:ret_x(geo_str(TkW));
+ y -> tcl2erl:ret_y(geo_str(TkW));
+ width -> tcl2erl:ret_width(geo_str(TkW));
+ height -> tcl2erl:ret_height(geo_str(TkW));
+ configure -> gstk_db:opt(DB,Gstkid,configure);
+ bg -> tcl2erl:ret_color([TkW," cg -bg"]);
+ map -> tcl2erl:ret_mapped(["winfo is ", TkW]);
+ iconify -> tcl2erl:ret_iconified(["wm st ", TkW]);
+ title -> tcl2erl:ret_str(["wm ti ", TkW]);
+ iconname -> tcl2erl:ret_str(["wm iconn ", TkW]);
+ iconbitmap -> tcl2erl:ret_str(["wm iconb ", TkW]);
+ iconmask -> tcl2erl:ret_str(["wm iconm ", TkW]);
+ setfocus -> tcl2erl:ret_focus(TkW, "focus");
+ _ -> {bad_result, {Gstkid#gstkid.objtype, invalid_option, Option}}
+ end.
+
+geo_str(TkW) ->
+ ["update idletasks;",?REGEXP,"[wm geometry ", TkW,
+ "] g w h x y;set tmp \"$w $h $x $y\""].
+
+
+
+%%----------------------------------------------------------------------
+%% PRIMITIVES
+%%----------------------------------------------------------------------
+
+%% Return {+,-}Int to be used in a geometry option
+signed(X) when X>=0 ->
+ [$+,integer_to_list(X)];
+signed(X) when X<0 ->
+ integer_to_list(X).
+
+%%----------------------------------------------------------------------
+%% Purpose: tcl/tk: wm .window geo sets WxH+x+y at one time.
+%% flushing every time is expensive. Do (almost) as much as
+%% possible in one operation.
+%%----------------------------------------------------------------------
+transform_geometry_opts(Opts) ->
+ {Geo,RestOpts} = collect_geo_opts(Opts,[],[]),
+ Geo2 = make_atomic(lists:sort(Geo)),
+ lists:append(Geo2,RestOpts).
+
+make_atomic([{height,H},{width,W},{x,X},{y,Y}]) ->
+ [{width_height,{W,H}},{xy,{X,Y}}];
+make_atomic([{height,H},{width,W}|XY]) ->
+ [{width_height,{W,H}}|XY];
+make_atomic([WH,{x,X},{y,Y}]) ->
+ [WH,{xy,{X,Y}}];
+make_atomic(L) -> L.
+
+%%----------------------------------------------------------------------
+%% Returns: {(list of x,y,width,height options),list of other opts}
+%%----------------------------------------------------------------------
+collect_geo_opts([{x,X}|Opts],Geo,Rest) ->
+ collect_geo_opts(Opts,[{x,X}|Geo],Rest);
+collect_geo_opts([{y,Y}|Opts],Geo,Rest) ->
+ collect_geo_opts(Opts,[{y,Y}|Geo],Rest);
+collect_geo_opts([{height,H}|Opts],Geo,Rest) ->
+ collect_geo_opts(Opts,[{height,H}|Geo],Rest);
+collect_geo_opts([{width,W}|Opts],Geo,Rest) ->
+ collect_geo_opts(Opts,[{width,W}|Geo],Rest);
+collect_geo_opts([Opt|Opts],Geo,Rest) ->
+ collect_geo_opts(Opts,Geo,[Opt|Rest]);
+collect_geo_opts([],Geo,Rest) -> {Geo,Rest}.
+
+%%% ----- Done -----