appmon.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,080 行 · 第 1/3 页
ERL
1,080 行
LMI = gs:create(menuitem, OptMenu, [{label, {text,"Load: linear"}}, {itemtype, radio}, {group, G2}, {data, {option, linear, [{load_scale,linear}]}}]), NodeMenuBtn = gs:create(menubutton, MenuBar, [{label, {text,"Nodes"}}]), NodeMenu = gs:create(menu, NodeMenuBtn, []), HelpMenuBtn = gs:create(menubutton, MenuBar, [{label, {text,"Help"}}, {side, right}]), HelpMenu = gs:create(menu, HelpMenuBtn, []), gs:create(menuitem, HelpMenu, [{label, {text,"Help"}}, {data, help}]), %% Meter HLed = trunc((?hMETER)/(?LEDCOUNT)), Leds = draw_leds(?LEDCOUNT, Canvas, ?yMETER, HLed, []), leds_down(Leds, ?LEDCOUNT, 0), gs:create(text, Canvas, [{coords, [{?xMETER, ?yMETER+HLed*?LEDCOUNT}]}, {anchor, nw}, {font, {screen,8}}, {text, "Load"}]), gs:create(text, Canvas, [{coords, [{?xMETER+?wMETER, ?yMETER}]}, {anchor, nw}, {font, {screen,8}}, {text, "Hi"}]), gs:create(text, Canvas, [{coords, [{?xMETER+?wMETER, ?yMETER+HLed*?LEDCOUNT}]}, {anchor, w}, {font, {screen,8}}, {text, "Lo"}]), %% Node label WNodeLbl = 8*length(NodeStr)+10, NLRect = gs:create(rectangle, Canvas, [{coords, [{?xNODELBL,?yNODELBL}, {?xNODELBL+WNodeLbl, ?yNODELBL+?hNODELBL}]}, {fill, black}]), Xc = ?xNODELBL + round(WNodeLbl/2), Yc = ?yNODELBL + round(?hNODELBL/2), NLText = gs:create(text, Canvas, [{text, NodeStr}, {fg, {250,235,215}}, {coords, [{Xc,Yc}]}, {anchor, c}]), NodeLbl = {NLRect, NLText}, gs:config(Win, {map, true}), #win{name=Node, window=Win, wwindow=?wWIN, hwindow=?hCANVAS, options=#options{single=SMI, many=MMI, time=TMI, queue=QMI, prog=PMI, linear=LMI}, canvas=Canvas, wcanvas=?wCANVAS, hcanvas=?hCANVAS, l1=L1, l2=L2, leds=Leds, nodelabel=NodeLbl, nodemenu=NodeMenu}.draw_leds(N, Canvas, Y, HLed, Leds) when N>0 -> Led = gs:create(rectangle, Canvas, [{coords, [{?xMETER,Y}, {?xMETER+?wMETER,Y+HLed}]}]), draw_leds(N-1, Canvas, Y+HLed, HLed, [Led | Leds]);draw_leds(0, _Canvas, _Y, _HLed, Leds) -> Leds.%%--Draw functions------------------------------------------------------%% Functions that modify the GUI and its data (win{})%% Display the node name in the window title%% (The name in the node label is changed by display_nodeup|nodedown)%% Used when a changing the node to displaydraw_nodename(GUI, Node) -> NodeStr = atom_to_list(Node), gs:config(GUI#win.window, {title, "APPMON: Overview on " ++ NodeStr}), GUI#win{name=Node}.%% Resize the canvas (when the window has been resized)draw_resize(GUI, W, H) -> Hc = H - ?hMENUBAR, gs:config(GUI#win.canvas, [{width, W}, {height, Hc}]), Yline1 = ?yNODELBL-?PAD, Yline2 = ?hCANVAS-?PAD, gs:config(GUI#win.l1, [{coords, [{0,Yline1},{W,Yline1}]}]), gs:config(GUI#win.l2, [{coords, [{0,Yline2},{W,Yline2}]}]), GUI#win{wwindow=W, hwindow=Hc}.%% Clear the GUI from applications and connecting linesdraw_clear(GUI) -> draw_clear2(GUI#win.appobjs), gs:config(GUI#win.canvas, [{hscroll, false}]), GUI#win{appobjs=[]}.draw_clear2([CBtn | AppObjs]) when is_record(CBtn, canvasbutton) -> gs:destroy(CBtn#canvasbutton.text), gs:destroy(CBtn#canvasbutton.ul), gs:destroy(CBtn#canvasbutton.ll), gs:destroy(CBtn#canvasbutton.rect), draw_clear2(AppObjs);draw_clear2([GSObj | AppObjs]) -> gs:destroy(GSObj), draw_clear2(AppObjs);draw_clear2([]) -> ignore.%% Display the applications, which are a list of tuples: {Pid,App,Descr}%% Display them in the reversed order to get them chronologically%% from left to right.draw_apps(GUI, Apps) -> {AppObjs, WCanvas} = draw_apps(GUI, lists:reverse(Apps), ?xNODELBL, undefined, 0, []), NewGUI = GUI#win{wcanvas=WCanvas, appobjs=AppObjs}, display_scrollbar(NewGUI), NewGUI.draw_apps(GUI, [App | Apps], X, Lx0, N, GSObjs) -> %% Some necessary data {_Pid, AppName, _Descr} = App, Text = atom_to_list(AppName), Width = max(8*length(Text)+10, ?wBTN), %% Connect the application to the node label with a line %% Lx0 = leftmost X coordinate (above previous application button) %% Lx = X coordinate, Ly1, Ly2 = top and bottom Y coordinates Lx = X + trunc(Width/2), Line = case N of %% First (leftmost application) - draw a vertical line %% between the node label and application button 0 -> Ly1 = ?yNODELBL + ?hNODELBL +?PAD, Ly2 = Ly1 + ?PAD2, gs:create(line, GUI#win.canvas, [{coords, [{Lx, Ly1}, {Lx, Ly2}]}]); %% Nth application, N>1 - draw a horizontal line from %% line connecting to the previous application button, %% to above this application button, then vertically down %% to the application button _ -> Ly1 = ?yNODELBL + ?hNODELBL + ?PAD + ?PAD2/2, Ly2 = Ly1 + ?PAD2/2, gs:create(line, GUI#win.canvas, [{coords, [{Lx0, Ly1}, {Lx, Ly1}, {Lx, Ly2}]}]) end, %% The application is represented using a 'canvasbutton' Data = {application, AppName, GUI#win.name}, AppBtn = canvasbutton(GUI#win.canvas, Text, X, ?yBTN, Width, ?hBTN, Data), draw_apps(GUI, Apps, X+Width+?PAD, Lx, N+1, [AppBtn, Line|GSObjs]);draw_apps(_GUI, [], X, _N, _Lx0, GSObjs) -> {GSObjs, X}.%%--Display functions---------------------------------------------------%% Functions that modify the GUI but not its data%% Add a new node to the Nodes menu%% Used when a new node has connecteddisplay_addnode([GUI|GUIs], Node) -> display_addnode(GUI, Node), display_addnode(GUIs, Node);display_addnode([], _Node) -> ignore;display_addnode(GUI, Node) -> Txt = "Show " ++ atom_to_list(Node), gs:create(menuitem, GUI#win.nodemenu, [{label, {text,Txt}}, {data, {node, Node, GUI#win.window}}]).%% Show that a node has come back updisplay_nodeup(GUI, Node) -> {Rect, Text} = GUI#win.nodelabel, %% Check coordinates for the rectangle and compute the new width [{L, T}, {_R, B}] = gs:read(Rect, coords), NodeStr = atom_to_list(Node), W = 8*length(NodeStr)+10, gs:config(Rect, [{coords, [{L, T}, {L+W, B}]}, {fill, black}]), gs:config(Text, [{text, NodeStr}, {fg, {250,235,215}}, {coords, [{L+round(W/2), T+round((?hNODELBL)/2)}]}]).%% Show that a node has gone downdisplay_nodedown(GUI) -> {Rect, Text} = GUI#win.nodelabel, [{L, T}, {_R, B}] = gs:read(Rect, coords), gs:config(Rect, [{coords, [{L, T}, {L+114, B}]}, {fill, gray}]), gs:config(Text, [{text, "No connection"}, {fg, black}, {coords, [{L+57, T+round((?hNODELBL)/2)}]}]).%% Add/remove scrollbars as necessarydisplay_scrollbar(GUI) -> WWindow = GUI#win.wwindow, HWindow = GUI#win.hwindow, WCanvas = GUI#win.wcanvas, HCanvas = GUI#win.hcanvas, if WCanvas>WWindow -> gs:config(GUI#win.canvas, [{hscroll, bottom}, {scrollregion,{0,0,WCanvas,HCanvas}}]); true -> gs:config(GUI#win.canvas, [{hscroll, false}]) end, if HCanvas>HWindow -> gs:config(GUI#win.canvas, [{vscroll, left}, {scrollregion,{0,0,WCanvas,HCanvas}}]); true -> gs:config(GUI#win.canvas, [{vscroll, false}]) end.%% Select option radio buttonsdisplay_setopt(GUI, Option) -> gs:config(radiobutton(GUI, Option), {select,true}).radiobutton(GUI, single) -> (GUI#win.options)#options.single;radiobutton(GUI, many) -> (GUI#win.options)#options.many;radiobutton(GUI, time) -> (GUI#win.options)#options.time;radiobutton(GUI, queue) -> (GUI#win.options)#options.queue;radiobutton(GUI, prog) -> (GUI#win.options)#options.prog;radiobutton(GUI, linear) -> (GUI#win.options)#options.linear.%% Display load%% Used when load information is received from the displayed node-define(highloadfg, {255,99,71}).-define(midloadfg, yellow).-define(lowloadfg, green).-define(highloadbg, {140,157,178}).-define(midloadbg, ?highloadbg).-define(lowloadbg, ?highloadbg).display_load(GUI, {Old, New}) -> if Old == New -> true; Old > New -> leds_down(GUI#win.leds, Old, New); true -> leds_up(GUI#win.leds, Old, New) end.leds_down(_Leds, Old, New) when Old == New -> done;leds_down(Leds, Old, New) when Old > New -> reset_led(Leds, Old), leds_down(Leds, Old-1, New).leds_up(_Leds, Old, New) when Old == New -> done;leds_up(Leds, Old, New) when Old < New -> set_led(Leds, Old), leds_up(Leds, Old+1, New).led_on_col(N) when N > 13 -> ?highloadfg;led_on_col(N) when N > 9 -> ?midloadfg;led_on_col(_) -> ?lowloadfg.led_off_col(N) when N > 13 -> ?highloadbg;led_off_col(N) when N > 9 -> ?midloadbg;led_off_col(_) -> ?lowloadbg.reset_led(_Leds, 0) -> ok;reset_led(Leds, N) -> gs:config(lists:nth(N, Leds), [{fill, led_off_col(N)}]).set_led(_Leds, 0) -> ok;set_led(Leds, N) -> gs:config(lists:nth(N, Leds), [{fill, led_on_col(N)}]).%%----------------------------------------------------------------------%% Utilities%%----------------------------------------------------------------------bcast(MNodes, Msg) -> lists:foreach(fun(MNode) -> case MNode#mnode.status of alive -> MNode#mnode.pid ! Msg; dead -> ignore end end, MNodes).max(X, Y) when X>Y -> X;max(_, Y) -> Y.%% parse_nodes(MNodes) -> NodeApps%% MNodes -> [#mnode{}]%% NodeApps -> [{Node, Status, Apps}]%% Node -> atom()%% Status -> alive | dead%% Apps -> [{Pid, App}]%% Pid -> pid()%% App -> atom()parse_nodes(MNodes) -> parse_nodes(MNodes, []).parse_nodes([MNode|MNodes], NodeApps) -> Apps = parse_apps(MNode#mnode.apps, []), parse_nodes(MNodes, [{MNode#mnode.name,MNode#mnode.status,Apps}|NodeApps]);parse_nodes([], NodeApps) -> NodeApps. parse_apps([{Pid, App, _Descr}|Rest], Apps) -> parse_apps(Rest, [{Pid, App}|Apps]);parse_apps([], Apps) -> Apps.%%----------------------------------------------------------------------%% Canvas buttons%%----------------------------------------------------------------------canvasbutton(Canvas, Text, X, Y, W, H, Data) -> %% Draw a rectangle (for event catching) Rect = gs:create(rectangle, Canvas, [{coords, [{X,Y}, {X+W,Y+H}]}, {fill, gs:read(Canvas, bg)}, {buttonpress, true}, {buttonrelease, true}]), %% Make the rectangle area look like a 3D button by using lines Ul = gs:create(line, Canvas, [{coords, [{X,Y+H},{X,Y},{X+W,Y}]}, {fg, white}, {width, 2}]), Ll = gs:create(line, Canvas, [{coords, [{X,Y+H},{X+W,Y+H},{X+W,Y}]}, {fg, {87,87,87}}, {width, 2}]), %% Write the text in the middle Xc = X + round(W/2), Yc = Y + round(H/2), T = gs:create(text, Canvas, [{text, Text}, {coords, [{Xc,Yc}]}, {anchor, c}, {buttonpress, true}, {buttonrelease, true}]), %% Create the canvasbutton object CBtn = #canvasbutton{text=T, ul=Ul, ll=Ll, rect=Rect, x=X, y=Y, w=W, h=H}, %% Configure the data gs:config(T, {data, {canvasbutton, CBtn, Data}}), gs:config(Rect, {data, {canvasbutton, CBtn, Data}}), CBtn.press(Canvasbutton) -> gs:config(Canvasbutton#canvasbutton.ul, {fg, {87,87,87}}), gs:config(Canvasbutton#canvasbutton.ll, {fg, white}).release(Canvasbutton) -> gs:config(Canvasbutton#canvasbutton.ul, {fg, white}), gs:config(Canvasbutton#canvasbutton.ll, {fg, {87,87,87}}).
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?