/*
* 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 haven.CharWnd.Study;
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 {
static public UI instance;
public RootWidget root;
public SlenHud slen;
public MenuGrid mnu;
public Speedget spd;
public Study study;
public WikiBrowser wiki;
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, lcc = Coord.z;
public Session sess;
public IHWindowParent chat;
public MapView mainview;
public boolean modshift, modctrl, modmeta, modsuper;
long lastevent = System.currentTimeMillis();
public Widget mouseon;
public FSMan fsm;
public Console cons = new WidgetConsole();
private Collection<AfterDraw> afterdraws = null;
public interface Receiver {
public void rcvmsg(int widget, String msg, Object... args);
}
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();
}
});
setcmd("fs", new Command() {
public void run(Console cons, String[] args) {
if((args.length >= 2) && (fsm != null)) {
if(Utils.atoi(args[1]) != 0)
fsm.setfs();
else
fsm.setwnd();
}
}
});
}
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) {
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 draw(GOut g) {
afterdraws = new LinkedList<AfterDraw>();
root.draw(g);
synchronized(afterdraws) {
for(AfterDraw ad : afterdraws) {
ad.draw(g);
}
}
afterdraws = null;
}
public void newwidget(int id, String type, Coord c, int parent, Object... args) throws InterruptedException {
WidgetFactory f;
if(type.indexOf('/') >= 0) {
int ver = -1, p;
if((p = type.indexOf(':')) > 0) {
ver = Integer.parseInt(type.substring(p + 1));
type = type.substring(0, p);
}
Resource res = Resource.load(type, ver);
res.loadwaitint();
f = res.layer(Resource.CodeEntry.class).get(WidgetFactory.class);
} else {
f = Widget.gettype(type);
}
synchronized(this) {
Widget pwdg = widgets.get(parent);
if(pwdg == null)
throw(new UIException("Null parent widget " + parent + " for " + id, type, args));
Widget wdg = f.create(c, pwdg, args);
bind(wdg, id);
wdg.binded();
if(wdg instanceof MapView)
mainview = (MapView)wdg;
}
}
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;
wdg.destroy();
wdg.unlink();
removeid(wdg);
}
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) {
Widget wdg;
synchronized(this) {
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();
modshift = (mod & InputEvent.SHIFT_DOWN_MASK) != 0;
modctrl = (mod & InputEvent.CTRL_DOWN_MASK) != 0;
modmeta = (mod & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_GRAPH_DOWN_MASK)) != 0;
/*
modsuper = (mod & InputEvent.SUPER_DOWN_MASK) != 0;
*/
}
public void type(KeyEvent ev) {
setmods(ev);
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);
if(keygrab == null) {
if(!root.keydown(ev))
root.globtype((char)0, ev);
} else {
keygrab.keydown(ev);
}
}
public void keyup(KeyEvent ev) {
setmods(ev);
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));
}
}