/* * 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.Resource.AButton; import java.awt.Color; import java.awt.event.KeyEvent; import java.awt.font.TextAttribute; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.Map; import java.util.TreeMap; public class MenuGrid extends Widget { private static final Color pressedColor = new Color(196, 196, 196, 196); public final static Tex bg = Resource.loadtex("gfx/hud/invsq"); public final static Coord bgsz = bg.sz().add(-1, -1); public final static Resource next = Resource.load("gfx/hud/sc-next"); public final static Resource bk = Resource.load("gfx/hud/sc-back"); public final static RichText.Foundry ttfnd = new RichText.Foundry(TextAttribute.FAMILY, "SansSerif", TextAttribute.SIZE, 10); private static Coord gsz = new Coord(4, 4); private Resource cur, pressed, dragging, layout[][] = new Resource[gsz.x][gsz.y]; private int curoff = 0; private Map<Character, Resource> hotmap = new TreeMap<Character, Resource>(); public ToolbarWnd digitbar; public ToolbarWnd functionbar; public ToolbarWnd numpadbar; static { Widget.addtype("scm", new WidgetFactory() { public Widget create(Coord c, Widget parent, Object[] args) { return(new MenuGrid(c, parent)); } }); } public class PaginaException extends RuntimeException { public Resource res; public PaginaException(Resource r) { super("Invalid pagina: " + r.name); res = r; } } private Resource[] cons(Resource p) { Resource[] cp = new Resource[0]; Resource[] all; { Collection<Resource> ta = new HashSet<Resource>(); Collection<Resource> open; synchronized(ui.sess.glob.paginae) { open = new HashSet<Resource>(ui.sess.glob.paginae); } while(!open.isEmpty()) { for(Resource r : open.toArray(cp)) { if(!r.loading) { AButton ad = r.layer(Resource.action); if(ad == null) throw(new PaginaException(r)); if((ad.parent != null) && !ta.contains(ad.parent)) open.add(ad.parent); ta.add(r); open.remove(r); } } } all = ta.toArray(cp); } Collection<Resource> tobe = new HashSet<Resource>(); for(Resource r : all) { if(r.layer(Resource.action).parent == p) tobe.add(r); } return(tobe.toArray(cp)); } public MenuGrid(Coord c, Widget parent) { super(c, bgsz.mul(gsz).add(1, 1), parent); cons(null); ui.mnu = this; ToolbarWnd.loadBelts(); digitbar = new ToolbarWnd(new Coord(0,300), ui.root, "toolbar1"); functionbar = new ToolbarWnd(new Coord(50,300), ui.root, "toolbar2", 2, KeyEvent.VK_F1, 12, new Coord(4, 10)); numpadbar = new ToolbarWnd(new Coord(100,300), ui.root, "toolbar3", 10, KeyEvent.VK_NUMPAD0){ protected void nextBelt(){ loadBelt((belt+1)%5+10); } protected void prevBelt(){ loadBelt((belt-1)%5+10); } }; } private static Comparator<Resource> sorter = new Comparator<Resource>() { public int compare(Resource a, Resource b) { AButton aa = a.layer(Resource.action), ab = b.layer(Resource.action); if((aa.ad.length == 0) && (ab.ad.length > 0)) return(-1); if((aa.ad.length > 0) && (ab.ad.length == 0)) return(1); return(aa.name.compareTo(ab.name)); } }; private void updlayout() { Resource[] cur = cons(this.cur); Arrays.sort(cur, sorter); int i; hotmap.clear(); for (i = 0; i< cur.length; i++){ Resource.AButton ad = cur[i].layer(Resource.action); if(ad.hk != 0) hotmap.put(Character.toUpperCase(ad.hk), cur[i]); } i = curoff; for(int y = 0; y < gsz.y; y++) { for(int x = 0; x < gsz.x; x++) { Resource btn = null; if((this.cur != null) && (x == gsz.x - 1) && (y == gsz.y - 1)) { btn = bk; } else if((cur.length > ((gsz.x * gsz.y) - 1)) && (x == gsz.x - 2) && (y == gsz.y - 1)) { btn = next; } else if(i < cur.length) { btn = cur[i++]; } layout[x][y] = btn; } } } private static Text rendertt(Resource res, boolean withpg) { Resource.AButton ad = res.layer(Resource.action); Resource.Pagina pg = res.layer(Resource.pagina); String tt = ad.name; int pos = tt.toUpperCase().indexOf(Character.toUpperCase(ad.hk)); String format = "$col[255,255,0]{%s}"; if(pos >= 0) tt = tt.substring(0, pos) + String.format(format, tt.charAt(pos)) + tt.substring(pos + 1); else if(ad.hk != 0) tt += " [" + String.format(format, ad.hk) + "]"; if(withpg && (pg != null)) { tt += "\n\n" + pg.text; } String mats, name = ad.name.toLowerCase(); if((mats = Config.crafts.get(name)) != null){ tt += "\n\n" + mats; } return(ttfnd.render(tt, 200)); } public void draw(GOut g) { updlayout(); for(int y = 0; y < gsz.y; y++) { for(int x = 0; x < gsz.x; x++) { Coord p = bgsz.mul(new Coord(x, y)); g.image(bg, p); Resource btn = layout[x][y]; if(btn != null) { Tex btex = btn.layer(Resource.imgc).tex(); if(btn == pressed) { g.chcolor(pressedColor); } if(Config.highlightSkills) g.chcolor(btn.getStateColor()); g.image(btex, p.add(1, 1)); g.chcolor(); } } } if(dragging != null) { final Tex dt = dragging.layer(Resource.imgc).tex(); ui.drawafter(new UI.AfterDraw() { public void draw(GOut g) { g.image(dt, ui.mc.add(dt.sz().div(2).inv())); } }); } } private Resource curttr = null; private boolean curttl = false; private Text curtt = null; private long hoverstart; public Object tooltip(Coord c, boolean again) { Resource res = bhit(c); long now = System.currentTimeMillis(); if((res != null) && (res.layer(Resource.action) != null)) { if(!again) hoverstart = now; boolean ttl = (now - hoverstart) > 500; if((res != curttr) || (ttl != curttl)) { curtt = rendertt(res, ttl); curttr = res; curttl = ttl; } return(curtt); } else { hoverstart = now; return(""); } } private Resource bhit(Coord c) { Coord bc = c.div(bgsz); if((bc.x >= 0) && (bc.y >= 0) && (bc.x < gsz.x) && (bc.y < gsz.y)) return(layout[bc.x][bc.y]); else return(null); } public boolean mousedown(Coord c, int button) { Resource h = bhit(c); if((button == 1) && (h != null)) { pressed = h; ui.grabmouse(this); } return(true); } public void mousemove(Coord c) { if((dragging == null) && (pressed != null)) { Resource h = bhit(c); if(h != pressed) dragging = pressed; } } public void use(Resource r) { if(cons(r).length > 0) { cur = r; curoff = 0; } else if(r == bk) { cur = cur.layer(Resource.action).parent; curoff = 0; } else if(r == next) { if((curoff + 14) >= cons(cur).length) curoff = 0; else curoff += 14; } else { AButton act = r.layer(Resource.action); if(act != null){ String [] ad = act.ad; if((ad == null) || (ad.length < 1)){return;} if(ad[0].equals("@")) { usecustom(ad); } else { int k = 0; if (ad[0].equals("crime")){k = -1;} if (ad[0].equals("tracking")){k = -2;} if (ad[0].equals("swim")){k = -3;} if(k<0){ synchronized (ui.sess.glob.buffs) { if(ui.sess.glob.buffs.containsKey(k)){ ui.sess.glob.buffs.remove(k); } else { Buff buff = new Buff(k, r.indir()); buff.major = true; ui.sess.glob.buffs.put(k, buff); } } } wdgmsg("act", (Object[])ad); } } else { String str = "Error while using belt item! Looks like inventory item got to be used as menu item. If you know steps to reproduce this - please report."; ui.cons.out.println(str); ui.slen.error(str); } } } private void usecustom(String[] list) { if(list[1].equals("radius")) { Config.showRadius = !Config.showRadius; String str = "Radius highlight is turned "+((Config.showRadius)?"ON":"OFF"); ui.cons.out.println(str); ui.slen.error(str); Config.saveOptions(); } else if(list[1].equals("hidden")) { Config.showHidden = !Config.showHidden; String str = "Hidden object highlight is turned "+((Config.showHidden)?"ON":"OFF"); ui.cons.out.println(str); ui.slen.error(str); Config.saveOptions(); } else if(list[1].equals("hide")) { for(int i=2;i<list.length;i++){ String item = list[i]; if(Config.hideObjectList.contains(item)){ Config.remhide(item); } else { Config.addhide(item); } } } else if(list[1].equals("simple plants")) { Config.simple_plants = !Config.simple_plants; String str = "Simplified plants is turned "+((Config.simple_plants)?"ON":"OFF"); ui.cons.out.println(str); ui.slen.error(str); Config.saveOptions(); } else if(list[1].equals("timers")) { TimerPanel.toggle(); } else if(list[1].equals("animal")) { Config.showBeast = !Config.showBeast; String str = "Animal highlight is turned "+((Config.showBeast)?"ON":"OFF"); ui.cons.out.println(str); ui.slen.error(str); Config.saveOptions(); } else if(list[1].equals("radar")) { Config.radar = !Config.radar; String str = "Radar is turned "+((Config.radar)?"ON":"OFF"); ui.cons.out.println(str); ui.slen.error(str); Config.saveOptions(); } else if(list[1].equals("study")) { ui.study.toggle(); } else if(list[1].equals("globalchat")) { IRChatHW.open(); } else if(list[1].equals("wiki")) { if(ui.wiki == null) { new WikiBrowser(MainFrame.getCenterPoint().sub(115, 75), Coord.z, ui.root); } else { ui.wiki.wdgmsg(ui.wiki.cbtn, "click"); } } use(null); } public boolean mouseup(Coord c, int button) { Resource h = bhit(c); if(button == 1) { if(dragging != null) { ui.dropthing(ui.root, ui.mc, dragging); dragging = pressed = null; } else if(pressed != null) { if(pressed == h) use(h); pressed = null; } ui.grabmouse(null); } updlayout(); return(true); } public void uimsg(String msg, Object... args) { if(msg == "goto") { String res = (String)args[0]; if(res.equals("")) cur = null; else cur = Resource.load(res); curoff = 0; } } public boolean globtype(char k, KeyEvent ev) { if(ev.isAltDown() || ev.isControlDown()){ return false; } if((k == 27) && (this.cur != null)) { this.cur = null; curoff = 0; updlayout(); return(true); } else if((k == 'N') && (layout[gsz.x - 2][gsz.y - 1] == next)) { use(next); return(true); } Resource r = hotmap.get(Character.toUpperCase(k)); if(r != null) { use(r); return(true); } return(false); } }