%% %% %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% %% -module(toolbar_graphics). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Erlang Toolbar % %%% Description %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Toolbar graphics. % The Toolbar window looks something like this: % % |-----------------------------| % | File Tools Help | % |-----------------------------| % | |-----| |-----| |-----| | % | | | | | | | | % | |Icon1| |Icon2|...|IconN| | % | |-----| |-----| |-----| | % |-----------------------------| % | Help text area | % |-----------------------------| % %%% Includes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % -include("toolbar.hrl"). % %%% Internal data structures %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Toolbar window record -record(tbwindow, {window,menubar,canvas,labelframe, label,helpmenu, no_of_buttons, min_height,min_width,cur_height,icons}). % %%% Constants %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Window width -define(width,215). % % Icon width and height -define(icon,34). % % Margin around icons -define(pad,0). % % Default label width and height -define(wlabel,50). -define(hlabel,15). % % Default button width and height -define(wbutton,50). -define(hbutton,30). % %%% Exports %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % -export([event/4]). -export([draw_window/1,redraw_window/2,already_added/2,add_icon/2]). -export([get_window/1]). -export([cursor/2]). -export([listen_configure/1]). -export([display_show/2,display_clear/1]). % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Exported functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %---------------------------------------- % event(Data,GsEvent,Data,Args) => Event % Data - term() % GsEvent - GS event % Data, Args - Data and Arg fields associated with the GS event % Event - {display,String} | display_clear | noevent | {start,{M,F,A}} | % update_toolbar | create_tool_file | add_gs_contribs | % {help,Html} | about_help | {redraw,{Width,Height}} | quit | % {newData,NewData} % String - string() % M, F - atom() Module and function name % A - [term()] Function argument % Html - string() HTML file | nofile % Width, Height - integer() % NewData - term() % Tries to convert a GS event to an internal toolbar event. The separation % is intented to keep the implementation details of the graphics hidden % for toolbar.erl. Pure graphical events triggered by the GS event will % be executed by this function. % The Data field is used for saving information between different events % (without having to use put/get or ets). Right now it is only used to save % the coordinates of the last canvasbutton pressed, making it possible to % check if the canvasbutton is released with the mouse moved outside the % button (= no action) or with the mouse still inside the button (= action). %---------------------------------------- %%% Mouse enters a icon, display short help message event(_LoopData,enter,{canvasbutton,_Cbtn,{_Start,{message,String}}},_Args) -> {display,String}; %% Mouse leaves a icon, clear display area event(_LoopData,leave,{canvasbutton,_Cbtn,_Data},_Args) -> display_clear; %% An icon is pressed, create graphical illusion of this event(_LoopData,buttonpress,{canvasbutton,Canvasbutton,_},_Args) -> canvasbutton:press(Canvasbutton), {newData,canvasbutton:read(Canvasbutton,coords)}; %% An icon is released, create graphical illusion of this event(LoopData,buttonrelease,{canvasbutton,Cbtn,{{start,Start},_Msg}}, [_,X,Y|_]) -> canvasbutton:release(Cbtn), case within(X,Y,LoopData) of true -> {start,Start}; false -> noevent end; %%% Update Toolbar button pressed event(_LoopData,click,_Data,["Update Toolbar"|_]) -> update_toolbar; %%% Tool configuration button pressed event(_LoopData,click,_Data,["Create Tool File..."|_]) -> create_tool_file; %%% Add GS contribution button pressed event(_LoopData,click,_Data,["Add GS Contributions"|_]) -> add_gs_contribs; %%% Help menu button selected event(_LoopData,click,{help,Html},_Args) -> {help,Html}; %%% About Help menu button selected event(_LoopData,click,about_help,_Args) -> about_help; %% Window resized, redraw it event(_LoopData,configure,_Data,[Width,Height|_]) -> {redraw,{Width,Height}}; %%% Quit button pressed event(_LoopData,click,_Data,["Quit"|_]) -> quit; %%% Window closed event(_LoopData,destroy,_Data,_Args) -> quit; event(_LoopData,_GsEvent,_Data,_Args) -> noevent. %============================================================================= % Main window functions %============================================================================= %---------------------------------------- % draw_window(S) => Window % S - pid() GS % Window - tbwindow record % This functions create the main window, initially without any tool icons %---------------------------------------- draw_window(S) -> Norm = ?icon + 2*?pad, %% Main window Win = gs:create(window,S,[{title,"Erlang Tools"},{width,?width}]), %% Menu bar with menu buttons Menubar = gs:create(menubar,Win,[]), %% File menu File = gs:create(menubutton,Menubar,[{label,{text,"File"}},{side,left}]), FileM = gs:create(menu,File,[]), gs:create(menuitem,FileM,[{label,{text,"Update Toolbar"}}]), gs:create(menuitem,FileM,[{label,{text,"Quit"}}]), %% Tools menu Tool = gs:create(menubutton,Menubar,[{label,{text,"Tools"}},{side,left}]), ToolM = gs:create(menu,Tool,[]), gs:create(menuitem,ToolM,[{label,{text,"Create Tool File..."}}]), gs:create(menuitem,ToolM,[{label,{text,"Add GS Contributions"}}]), %% Help menu Help = gs:create(menubutton,Menubar,[{label,{text,"Help"}},{side,right}]), HelpM = gs:create(menu,Help,[]), gs:create(menuitem,HelpM,[{label,{text,"About..."}}, {data,about_help}]), gs:create(menuitem,HelpM,[{label,{text,"Toolbar"}}, {data,{help,toolbar_lib:help_file()}}]), gs:create(menuitem,HelpM,[{label,{text,"OTP"}}, {data,{help,toolbar_lib:otp_file()}}]), gs:create(menuitem,HelpM,[{itemtype,separator}]), %% Check height of menu bar H = gs:read(Menubar,height), %% Now the height of the window can be computed Height = H+Norm+?hlabel+2*?pad, gs:config(Win,{height,Height}), %% Canvas, here will the Tool canvasbuttons be inserted Canvas = gs:create(canvas,Win,[{width,?width},{height,Norm},{x,0},{y,H}]), %% Label for displaying help messages and the frame containing it LabelF = gs:create(frame,Win,[{bg,green},{bw,1}, {width,?width},{height,?hlabel+2*?pad}, {x,0},{y,H+Norm}]), Label = gs:create(label,LabelF,[{align,w},{height,?hlabel}, {width,?width},{x,?pad},{y,?pad}, {label,{text,string:copies(" ",30)}}]), gs:config(Win,{map,true}), #tbwindow{window=Win, menubar=Menubar,canvas=Canvas,labelframe=LabelF, label=Label,helpmenu=HelpM, no_of_buttons=0, min_height=Height,min_width=?width,cur_height=Height, icons=[]}. %---------------------------------------- % redraw_window(Window,{NewWidth,NewHeight}) => NewWindow % Window, NewWindow - tbwindow record % NewWidth, NewHeight - integer() % Redraw main window contents according to a new size %---------------------------------------- redraw_window(Window,{NewWidth,NewHeight}) -> MinWidth = Window#tbwindow.min_width, if NewWidth= true; true -> gs:config(Window#tbwindow.canvas,{width,NewWidth}), gs:config(Window#tbwindow.labelframe,{width,NewWidth}), gs:config(Window#tbwindow.label,{width,NewWidth-2*?pad}) end, MinHeight = Window#tbwindow.min_height, if NewHeight= Window; true -> %% Compute size difference Diff = NewHeight - Window#tbwindow.cur_height, %% Resize button frame Canvas = Window#tbwindow.canvas, gs:config(Canvas,{height,gs:read(Canvas,height)+Diff}), %% Move label frame accordingly LabelF = Window#tbwindow.labelframe, gs:config(LabelF,{y,gs:read(LabelF,y)+Diff}), %% Return updated tbwindow record Window#tbwindow{cur_height=NewHeight} end. %---------------------------------------- % already_added(Window,ToolInfo) => true | false % Window - tbwindow record % ToolInfo - toolinfo record % Returns true if ToolInfo contains information about a tool that % is already included in Window %---------------------------------------- already_added(Window,ToolInfo) -> already_added2(Window#tbwindow.icons,ToolInfo#toolinfo.tool). %---------------------------------------- % already_added2(ToolInfos,Tool) => true | false % ToolInfos - [toolinfo record] % Tool - atom() Tool name %---------------------------------------- already_added2([#toolinfo{tool=Tool}|_Rest],Tool) -> true; already_added2([_|Rest],Tool) -> already_added2(Rest,Tool); already_added2([],_ToolInfo) -> false. %---------------------------------------- % add_icon(Window,ToolInfo) => NewWindow % Window, NewWindow - tbwindow record % ToolInfo - toolinfo record % Add an icon to the main window %---------------------------------------- add_icon(Window,ToolInfo) -> Norm = ?icon + 2*?pad, %% Extend window if necessary N = Window#tbwindow.no_of_buttons, ReqWidth = N*Norm+Norm, CurWidth = gs:read(Window#tbwindow.window,width), if ReqWidth>CurWidth -> gs:config(Window#tbwindow.window,{width,ReqWidth}), gs:config(Window#tbwindow.canvas,{width,ReqWidth}), gs:config(Window#tbwindow.labelframe,{width,ReqWidth}), gs:config(Window#tbwindow.label,{width,ReqWidth-2*?pad}); true -> true end, %% Insert icon into button frame canvasbutton:create(Window#tbwindow.canvas, [{image,ToolInfo#toolinfo.icon}, {x,N*Norm+?pad},{y,?pad}, {width,?icon},{height,?icon}, {data,{{start,ToolInfo#toolinfo.start}, {message,ToolInfo#toolinfo.message}}}]), %% Insert tool name into help menu (if there is any help available) case ToolInfo#toolinfo.html of nofile -> true; Html -> gs:create(menuitem,Window#tbwindow.helpmenu, [{label,{text,ToolInfo#toolinfo.tool}}, {data,{help,Html}}]) end, MinWidth = gs:read(Window#tbwindow.window,width), Window#tbwindow{no_of_buttons=N+1,min_width=MinWidth, icons=[ToolInfo|Window#tbwindow.icons]}. %---------------------------------------- % get_window(Window) -> gs_obj() % Window - tbwindow record %---------------------------------------- get_window(Window) -> Window#tbwindow.window. %---------------------------------------- % cursor(Window,Cursor) % Window - tbwindow record % Cursor - arrow | busy %---------------------------------------- cursor(Window,Cursor) -> gs:config(Window#tbwindow.window,{cursor,Cursor}). %---------------------------------------- % listen_configure(Window) % Window - tbwindow record % Configure Window to listen for configure events %---------------------------------------- listen_configure(Window) -> gs:config(Window#tbwindow.window,{configure,true}). %---------------------------------------- % display_show(Window,Text) % Window - tbwindow record % Text - string() % Display text in the help text area %---------------------------------------- display_show(Window,Text) -> gs:config(Window#tbwindow.label,{label,{text,Text}}). %---------------------------------------- % display_clear(Window) % Window - tbwindow record % Clear the help text area %---------------------------------------- display_clear(Window) -> display_show(Window,""). %%% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %---------------------------------------- % within(X,Y,[{Left,Top},{Right,Bot}]) => true | false % Return true if {X,Y} is within the given rectangle. %---------------------------------------- within(X,Y,[{L,T},{R,B}]) -> if X>=L, X==T, Y= true; true -> false end.