/* * This file is part of the Haven & Hearth game client. * Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and * Björn Johannessen <johannessen.bjorn@gmail.com> * * Redistribution and/or modification of this file is subject to the * terms of the GNU Lesser General Public License, version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Other parts of this source tree adhere to other copying * rights. Please see the file `COPYING' in the root directory of the * source tree for details. * * A copy the GNU Lesser General Public License is distributed along * with the source tree of which this file is a part in the file * `doc/LPGL-3'. If it is missing for any reason, please see the Free * Software Foundation's website at <http://www.fsf.org/>, or write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ package haven; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.TreeMap; public class UI { public static UI instance; public GameUI gui; public RootWidget root; private Widget keygrab, mousegrab; public Map<Integer, Widget> widgets = new TreeMap<Integer, Widget>(); public Map<Widget, Integer> rwidgets = new HashMap<Widget, Integer>(); Receiver rcvr; public Coord mc = Coord.z, lcc = Coord.z; public Session sess; public boolean modshift, modctrl, modmeta, modsuper; public Object lasttip; long lastevent, lasttick; public Widget mouseon; public Console cons = new WidgetConsole(); private Collection<AfterDraw> afterdraws = new LinkedList<AfterDraw>(); private Collection<AfterDraw> afterttdraws = new LinkedList<AfterDraw>(); public MenuGrid mnu; public final ActAudio audio = new ActAudio(); { lastevent = lasttick = System.currentTimeMillis(); } public interface Receiver { public void rcvmsg(int widget, String msg, Object... args); } public interface Runner { public Session run(UI ui) throws InterruptedException; } public interface AfterDraw { public void draw(GOut g); } private class WidgetConsole extends Console { { setcmd("q", new Command() { public void run(Console cons, String[] args) { HackThread.tg().interrupt(); } }); setcmd("lo", new Command() { public void run(Console cons, String[] args) { sess.close(); } }); } private void findcmds(Map<String, Command> map, Widget wdg) { if(wdg instanceof Directory) { Map<String, Command> cmds = ((Directory)wdg).findcmds(); synchronized(cmds) { map.putAll(cmds); } } for(Widget ch = wdg.child; ch != null; ch = ch.next) findcmds(map, ch); } public Map<String, Command> findcmds() { Map<String, Command> ret = super.findcmds(); findcmds(ret, root); return(ret); } } @SuppressWarnings("serial") public static class UIException extends RuntimeException { public String mname; public Object[] args; public UIException(String message, String mname, Object... args) { super(message); this.mname = mname; this.args = args; } } public UI(Coord sz, Session sess) { UI.instance = this; root = new RootWidget(this, sz); widgets.put(0, root); rwidgets.put(root, 0); this.sess = sess; } public void setreceiver(Receiver rcvr) { this.rcvr = rcvr; } public void bind(Widget w, int id) { widgets.put(id, w); rwidgets.put(w, id); } public void drawafter(AfterDraw ad) { synchronized(afterdraws) { afterdraws.add(ad); } } public void drawaftertt(AfterDraw ad) { synchronized(afterttdraws) { afterttdraws.add(ad); } } public void lastdraw(GOut g) { synchronized(afterttdraws) { for(AfterDraw ad : afterttdraws) ad.draw(g); afterttdraws.clear(); } } public void tick() { long now = System.currentTimeMillis(); root.tick((now - lasttick) / 1000.0); lasttick = now; } public void draw(GOut g) { root.draw(g); synchronized(afterdraws) { for(AfterDraw ad : afterdraws) ad.draw(g); afterdraws.clear(); } } public void newwidget(int id, String type, int parent, Object[] pargs, Object... cargs) throws InterruptedException { synchronized(this) { Widget pwdg = widgets.get(parent); if(pwdg == null) throw(new UIException("Null parent widget " + parent + " for " + id, type, cargs)); Widget wdg = pwdg.makechild(type.intern(), pargs, cargs); bind(wdg, id); } } public void grabmouse(Widget wdg) { mousegrab = wdg; } public void grabkeys(Widget wdg) { keygrab = wdg; } private void removeid(Widget wdg) { if(rwidgets.containsKey(wdg)) { int id = rwidgets.get(wdg); widgets.remove(id); rwidgets.remove(wdg); } for(Widget child = wdg.child; child != null; child = child.next) removeid(child); } public void destroy(Widget wdg) { if((mousegrab != null) && mousegrab.hasparent(wdg)) mousegrab = null; if((keygrab != null) && keygrab.hasparent(wdg)) keygrab = null; removeid(wdg); wdg.reqdestroy(); } public void destroy(int id) { synchronized(this) { if(widgets.containsKey(id)) { Widget wdg = widgets.get(id); destroy(wdg); } } } public void wdgmsg(Widget sender, String msg, Object... args) { int id; synchronized(this) { if(!rwidgets.containsKey(sender)) throw(new UIException("Wdgmsg sender (" + sender.getClass().getName() + ") is not in rwidgets", msg, args)); id = rwidgets.get(sender); } if(rcvr != null) rcvr.rcvmsg(id, msg, args); } public void uimsg(int id, String msg, Object... args) { synchronized(this) { Widget wdg = widgets.get(id); if(wdg != null) wdg.uimsg(msg.intern(), args); else throw(new UIException("Uimsg to non-existent widget " + id, msg, args)); } } private void setmods(InputEvent ev) { int mod = ev.getModifiersEx(); Debug.kf1 = modshift = (mod & InputEvent.SHIFT_DOWN_MASK) != 0; Debug.kf2 = modctrl = (mod & InputEvent.CTRL_DOWN_MASK) != 0; Debug.kf3 = modmeta = (mod & (InputEvent.META_DOWN_MASK | InputEvent.ALT_DOWN_MASK)) != 0; /* Debug.kf4 = modsuper = (mod & InputEvent.SUPER_DOWN_MASK) != 0; */ } private int kcode = 0; public void type(KeyEvent ev) { setmods(ev); ev.setKeyCode(kcode); if(keygrab == null) { if(!root.type(ev.getKeyChar(), ev)) root.globtype(ev.getKeyChar(), ev); } else { keygrab.type(ev.getKeyChar(), ev); } } public void keydown(KeyEvent ev) { setmods(ev); kcode = ev.getKeyCode(); if(keygrab == null) { if(!root.keydown(ev)) root.globtype((char)0, ev); } else { keygrab.keydown(ev); } } public void keyup(KeyEvent ev) { setmods(ev); kcode = 0; if(keygrab == null) root.keyup(ev); else keygrab.keyup(ev); } private Coord wdgxlate(Coord c, Widget wdg) { return(c.add(wdg.c.inv()).add(wdg.parent.rootpos().inv())); } public boolean dropthing(Widget w, Coord c, Object thing) { if(w instanceof DropTarget) { if(((DropTarget)w).dropthing(c, thing)) return(true); } for(Widget wdg = w.lchild; wdg != null; wdg = wdg.prev) { Coord cc = w.xlate(wdg.c, true); if(c.isect(cc, wdg.sz)) { if(dropthing(wdg, c.add(cc.inv()), thing)) return(true); } } return(false); } public void mousedown(MouseEvent ev, Coord c, int button) { setmods(ev); lcc = mc = c; if(mousegrab == null) root.mousedown(c, button); else mousegrab.mousedown(wdgxlate(c, mousegrab), button); } public void mouseup(MouseEvent ev, Coord c, int button) { setmods(ev); mc = c; if(mousegrab == null) root.mouseup(c, button); else mousegrab.mouseup(wdgxlate(c, mousegrab), button); } public void mousemove(MouseEvent ev, Coord c) { setmods(ev); mc = c; if(mousegrab == null) root.mousemove(c); else mousegrab.mousemove(wdgxlate(c, mousegrab)); } public void mousewheel(MouseEvent ev, Coord c, int amount) { setmods(ev); lcc = mc = c; if(mousegrab == null) root.mousewheel(c, amount); else mousegrab.mousewheel(wdgxlate(c, mousegrab), amount); } public int modflags() { return((modshift?1:0) | (modctrl?2:0) | (modmeta?4:0) | (modsuper?8:0)); } public void message(String str, GameUI.MsgType type) { if((cons!=null) && (gui!=null)){ gui.message(str, type); } } public void message(String str, Color msgColor) { if((cons!=null) && (gui!=null)){ gui.message(str, msgColor); } } public static boolean isCursor(String name) { return instance != null && instance.root != null && instance.root.cursor.name.equals(name); } public void destroy() { audio.clear(); } public static class Cursor { public static final String SIFTING = "gfx/hud/curs/sft"; public static final String GOBBLE = "gfx/hud/curs/eat"; } }