diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/gs/src/gstk_window.erl | |
download | otp-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.erl | 369 |
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 ----- |