X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjexer%2FTApplication.java;h=264b8c8220e3fddb3b062e612a97ed74761f22c2;hb=2a92cf977ee2ae37d8302a294c6338fa51a5ca45;hp=96f91f2943696d38a7f6e4d72b8fab2036da3482;hpb=a69ed767c9c07cf35cf1c5f7821fc009cfe79cd2;p=fanfix.git diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index 96f91f2..264b8c8 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -28,12 +28,14 @@ */ package jexer; +import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.UnsupportedEncodingException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -636,6 +638,8 @@ public class TApplication implements Runnable { * Run this application until it exits. */ public void run() { + // System.err.println("*** TApplication.run() begins ***"); + // Start the main consumer thread primaryEventHandler = new WidgetEventHandler(this, true); (new Thread(primaryEventHandler)).start(); @@ -719,6 +723,11 @@ public class TApplication implements Runnable { // resources. closeAllWindows(); + // Give the overarching application an opportunity to release + // resources. + onExit(); + + // System.err.println("*** TApplication.run() exits ***"); } // ------------------------------------------------------------------------ @@ -812,11 +821,23 @@ public class TApplication implements Runnable { closeAllWindows(); return true; } + if (menu.getId() == TMenu.MID_ABOUT) { + showAboutDialog(); + return true; + } if (menu.getId() == TMenu.MID_REPAINT) { getScreen().clearPhysical(); doRepaint(); return true; } + if (menu.getId() == TMenu.MID_VIEW_IMAGE) { + openImage(); + return true; + } + if (menu.getId() == TMenu.MID_CHANGE_FONT) { + new TFontChooserWindow(this); + return true; + } return false; } @@ -900,7 +921,7 @@ public class TApplication implements Runnable { // Abort everything if (event instanceof TCommandEvent) { TCommandEvent command = (TCommandEvent) event; - if (command.getCmd().equals(cmAbort)) { + if (command.equals(cmAbort)) { exit(); return; } @@ -922,6 +943,7 @@ public class TApplication implements Runnable { if (desktop != null) { desktop.setDimensions(0, 0, resize.getWidth(), resize.getHeight() - 1); + desktop.onResize(resize); } // Change menu edges if needed. @@ -969,7 +991,10 @@ public class TApplication implements Runnable { mouseX = mouse.getX(); mouseY = mouse.getY(); } else { - if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { + if ((mouse.getType() == TMouseEvent.Type.MOUSE_DOWN) + && (!mouse.isMouseWheelUp()) + && (!mouse.isMouseWheelDown()) + ) { if ((mouse.getTime().getTime() - lastMouseUpTime) < doubleClickTime) { @@ -1151,7 +1176,10 @@ public class TApplication implements Runnable { mouseX = mouse.getX(); mouseY = mouse.getY(); } else { - if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { + if ((mouse.getType() == TMouseEvent.Type.MOUSE_DOWN) + && (!mouse.isMouseWheelUp()) + && (!mouse.isMouseWheelDown()) + ) { if ((mouse.getTime().getTime() - lastMouseUpTime) < doubleClickTime) { @@ -1314,6 +1342,7 @@ public class TApplication implements Runnable { synchronized (invokeLaters) { invokeLaters.add(command); } + doRepaint(); } /** @@ -1452,6 +1481,53 @@ public class TApplication implements Runnable { this.focusFollowsMouse = focusFollowsMouse; } + /** + * Display the about dialog. + */ + protected void showAboutDialog() { + String version = getClass().getPackage().getImplementationVersion(); + if (version == null) { + // This is Java 9+, use a hardcoded string here. + version = "0.3.1"; + } + messageBox(i18n.getString("aboutDialogTitle"), + MessageFormat.format(i18n.getString("aboutDialogText"), version), + TMessageBox.Type.OK); + } + + /** + * Handle the Tool | Open image menu item. + */ + private void openImage() { + try { + List filters = new ArrayList(); + filters.add("^.*\\.[Jj][Pp][Gg]$"); + filters.add("^.*\\.[Jj][Pp][Ee][Gg]$"); + filters.add("^.*\\.[Pp][Nn][Gg]$"); + filters.add("^.*\\.[Gg][Ii][Ff]$"); + filters.add("^.*\\.[Bb][Mm][Pp]$"); + String filename = fileOpenBox(".", TFileOpenBox.Type.OPEN, filters); + if (filename != null) { + new TImageWindow(this, new File(filename)); + } + } catch (IOException e) { + // Show this exception to the user. + new TExceptionDialog(this, e); + } + } + + /** + * Check if application is still running. + * + * @return true if the application is running + */ + public final boolean isRunning() { + if (quit == true) { + return false; + } + return true; + } + // ------------------------------------------------------------------------ // Screen refresh loop ---------------------------------------------------- // ------------------------------------------------------------------------ @@ -1466,7 +1542,26 @@ public class TApplication implements Runnable { if (debugThreads) { System.err.printf("%d %s invertCell() %d %d\n", System.currentTimeMillis(), Thread.currentThread(), x, y); + + if (activeWindow != null) { + System.err.println("activeWindow.hasHiddenMouse() " + + activeWindow.hasHiddenMouse()); + } } + + // If this cell is on top of a visible window that has requested a + // hidden mouse, bail out. + if ((activeWindow != null) && (activeMenu == null)) { + if ((activeWindow.hasHiddenMouse() == true) + && (x > activeWindow.getX()) + && (x < activeWindow.getX() + activeWindow.getWidth() - 1) + && (y > activeWindow.getY()) + && (y < activeWindow.getY() + activeWindow.getHeight() - 1) + ) { + return; + } + } + Cell cell = getScreen().getCharXY(x, y); if (cell.isImage()) { cell.invertImage(); @@ -1702,6 +1797,10 @@ public class TApplication implements Runnable { // Flush the screen contents if ((images.size() > 0) || getScreen().isDirty()) { + if (debugThreads) { + System.err.printf("%d %s backend.flushScreen()\n", + System.currentTimeMillis(), Thread.currentThread()); + } backend.flushScreen(); } @@ -1718,6 +1817,14 @@ public class TApplication implements Runnable { } } + /** + * Subclasses can use this hook to cleanup resources. Called as the last + * step of TApplication.run(). + */ + public void onExit() { + // Default does nothing. + } + // ------------------------------------------------------------------------ // TWindow management ----------------------------------------------------- // ------------------------------------------------------------------------ @@ -1833,7 +1940,8 @@ public class TApplication implements Runnable { assert (!window.isActive()); if (activeWindow != null) { - assert (activeWindow.getZ() == 0); + // TODO: see if this assertion is really necessary. + // assert (activeWindow.getZ() == 0); activeWindow.setActive(false); @@ -1959,29 +2067,33 @@ public class TApplication implements Runnable { int z = window.getZ(); window.setZ(-1); window.onUnfocus(); + windows.remove(window); Collections.sort(windows); - windows.remove(0); activeWindow = null; + int newZ = 0; + boolean foundNextWindow = false; + for (TWindow w: windows) { + w.setZ(newZ); + newZ++; // Do not activate a hidden window. if (w.isHidden()) { continue; } - if (w.getZ() > z) { - w.setZ(w.getZ() - 1); - if (w.getZ() == 0) { - w.setActive(true); - w.onFocus(); - assert (activeWindow == null); - activeWindow = w; - } else { - if (w.isActive()) { - w.setActive(false); - w.onUnfocus(); - } - } + if (foundNextWindow == false) { + foundNextWindow = true; + w.setActive(true); + w.onFocus(); + assert (activeWindow == null); + activeWindow = w; + continue; + } + + if (w.isActive()) { + w.setActive(false); + w.onUnfocus(); } } } @@ -2162,6 +2274,21 @@ public class TApplication implements Runnable { return false; } + /** + * Check if there is a window with overridden menu flag on top. + * + * @return true if the active window is overriding the menu + */ + private boolean overrideMenuWindowActive() { + if (activeWindow != null) { + if (activeWindow.hasOverriddenMenu()) { + return true; + } + } + + return false; + } + /** * Close all open windows. */ @@ -2492,6 +2619,7 @@ public class TApplication implements Runnable { if ((mouse.getType() == TMouseEvent.Type.MOUSE_DOWN) && (mouse.isMouse1()) && (!modalWindowActive()) + && (!overrideMenuWindowActive()) && (mouse.getAbsoluteY() == 0) ) { @@ -2557,7 +2685,7 @@ public class TApplication implements Runnable { if (((focusFollowsMouse == true) && (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION)) - || (mouse.getType() == TMouseEvent.Type.MOUSE_UP) + || (mouse.getType() == TMouseEvent.Type.MOUSE_DOWN) ) { synchronized (windows) { Collections.sort(windows); @@ -2873,6 +3001,22 @@ public class TApplication implements Runnable { return menu; } + /** + * Convenience function to add a default tools (hamburger) menu. + * + * @return the new menu + */ + public final TMenu addToolMenu() { + TMenu toolMenu = addMenu(i18n.getString("toolMenuTitle")); + toolMenu.addDefaultItem(TMenu.MID_REPAINT); + toolMenu.addDefaultItem(TMenu.MID_VIEW_IMAGE); + toolMenu.addDefaultItem(TMenu.MID_CHANGE_FONT); + TStatusBar toolStatusBar = toolMenu.newStatusBar(i18n. + getString("toolMenuStatus")); + toolStatusBar.addShortcutKeypress(kbF1, cmHelp, i18n.getString("Help")); + return toolMenu; + } + /** * Convenience function to add a default "File" menu. * @@ -3222,7 +3366,7 @@ public class TApplication implements Runnable { public final TTerminalWindow openTerminal(final int x, final int y, final int flags, final String commandLine) { - return new TTerminalWindow(this, x, y, flags, commandLine.split("\\s")); + return new TTerminalWindow(this, x, y, flags, commandLine.split("\\s+")); } /** @@ -3239,7 +3383,7 @@ public class TApplication implements Runnable { public final TTerminalWindow openTerminal(final int x, final int y, final int flags, final String commandLine, final boolean closeOnExit) { - return new TTerminalWindow(this, x, y, flags, commandLine.split("\\s"), + return new TTerminalWindow(this, x, y, flags, commandLine.split("\\s+"), closeOnExit); }