It is currently 26 Aug 2025, 17:48
   
Text Size

Aug 2011 GUI Overhaul

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Aug 2011 GUI Overhaul

Postby Braids » 17 Aug 2011, 22:07

this topic started in the main Forge forum under the subject Know any UI Developers? (Bounty Inside). it moved here because it was getting very technical.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Aug 2011 GUI Overhaul

Postby Braids » 18 Aug 2011, 00:01

i now have a class named SplashFrame with some contents, but i'm having trouble with the progress dialog. because it's a window, i can't add it to the splash frame as a component. and i don't want to write a new progress monitor as a component.

i'm thinking i can just use the existing dialog, remove its window decorations, resize it, and move it somewhere near the SplashFrame. i may have to cut the bottom 90 pixels from moomarc's splash image, where the progress bar was intended to go. i don't know what to do about the background for the progress dialog yet. i don't know if dialogs support JLayeredPane. if they don't, i may need an "average color" for the background of the progress dialog.

i can't remove the window decorations from the progress dialog without rewriting some of it.

i can't fit much text in the SplashFrame.

and now for some good news.

1. CardReader no longer creates its own progress monitor. it acquires an existing one from the FView. CardReader no longer depends on swing. and it still passes its unit tests! :D

2. MultiPhaseProgressMonitorWithETA now updates itself in the swing event dispatch thread correctly. it smartly checks whether it is in the thread for its constructor and operations that update the GUI. for the latter, it uses SwingUtilities to make sure to execute the GUI code in the correct thread.

these changes have yet to be committed.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Aug 2011 GUI Overhaul

Postby Rob Cashwalker » 18 Aug 2011, 00:57

How about rewrite the progress bar dialog to have a flag property for splash screen mode vs regular progress bar mode?
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: Aug 2011 GUI Overhaul

Postby Braids » 18 Aug 2011, 01:41

Rob Cashwalker wrote:How about rewrite the progress bar dialog to have a flag property for splash screen mode vs regular progress bar mode?
it's hard to use a flag to determine which class to extend (JComponent or JDialog).

i have come up with a simpler solution. i just place the splash screen below the progress bar. it still needs work, but i think i'd like to pass that on to someone else.

i'll be posting the diffs here shortly so they can be reviewed before i commit them.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Code Review for initial splash window

Postby Braids » 18 Aug 2011, 01:55

i have tried to place these in order of importance. please review and comment. thank you!

please note that i intentionally did not place the progress bar inside the SplashFrame; instead, i simply placed the SplashFrame below the progress dialog. this negated the need to rewrite progress bar as a component instead of a dialog.

i'm mostly looking for comments on proper swing usage, and proper swing thread usage. thanks.

Code: Select all
Index: src/main/java/net/slightlymagic/braids/util/UtilFunctions.java
===================================================================
--- src/main/java/net/slightlymagic/braids/util/UtilFunctions.java   (revision 9802)
+++ src/main/java/net/slightlymagic/braids/util/UtilFunctions.java   (working copy)
@@ -1,9 +1,12 @@
 package net.slightlymagic.braids.util;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import javax.swing.SwingUtilities;
+
 /**
  * Some general-purpose functions.
  */
@@ -40,6 +43,30 @@
       throw exn;
    }
    
+   /**
+    * Invoke the given Runnable in an Event Dispatch Thread and wait for it
+    * to finish.
+    *
+    * Exceptions generated by SwingUtilities.invokeAndWait (if used), are
+    * rethrown as RuntimeExceptions.
+    *
+    * @param proc  the Runnable to run
+    */
+    public static void invokeInEventDispatchThreadAndWait(final Runnable proc) {
+        if (SwingUtilities.isEventDispatchThread()) {
+            // Just run in the current thread.
+            proc.run();
+        }
+        else {
+            try {
+                SwingUtilities.invokeAndWait(proc);
+            } catch (InterruptedException exn) {
+                throw new RuntimeException(exn);
+            } catch (InvocationTargetException exn) {
+                throw new RuntimeException(exn);
+            }
+        }
+    }
 
    /**
     * Create an array from the (rest of) an iterator's output;
Index: src/main/java/forge/view/swing/SplashFrame.java
===================================================================
--- src/main/java/forge/view/swing/SplashFrame.java   (revision 0)
+++ src/main/java/forge/view/swing/SplashFrame.java   (revision 0)
@@ -0,0 +1,107 @@
+package forge.view.swing;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Rectangle;
+
+import javax.swing.ImageIcon;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+import javax.swing.border.EmptyBorder;
+
+import forge.gui.MultiPhaseProgressMonitorWithETA;
+
+/**
+ * Shows the splash frame as the application starts.
+ */
+@SuppressWarnings("serial")
+public class SplashFrame extends JFrame {
+
+    private static final Color WHITE_COLOR = new Color(255, 255, 255);
+    private static final int DISCLAIMER_EAST_WEST_PADDING_PX = 40; // NOPMD by Braids on 8/17/11 9:06 PM
+    private static final int DISCLAIMER_FONT_SIZE = 9; // NOPMD by Braids on 8/17/11 9:06 PM
+    private static final int DISCLAIMER_NORTH_PADDING_PX = 300; // NOPMD by Braids on 8/17/11 9:06 PM
+    private static final int DISCLAIMER_HEIGHT_PX = 20; // NOPMD by Braids on 8/17/11 9:06 PM
+
+    private MultiPhaseProgressMonitorWithETA monitor;
+
+
+    /**
+     * Create the frame.
+     */
+    public SplashFrame() {
+        super();
+        setUndecorated(true);
+
+        final ImageIcon bgIcon = new ImageIcon("res/images/ui/forgeSplash by moomarc.jpg");
+
+        final int splashWidthPx = bgIcon.getIconWidth();
+        final int splashHeightPx = bgIcon.getIconHeight();
+
+        monitor = new MultiPhaseProgressMonitorWithETA("Loading card database", 1,
+                1, 1.0f);
+
+        final JDialog progressBarDialog = monitor.getDialog();
+
+        final Rectangle progressRect = progressBarDialog.getBounds();
+
+        setMinimumSize(new Dimension(splashWidthPx, splashHeightPx));
+        setLocation(progressRect.x, progressRect.y + progressRect.height);
+
+        setResizable(false);
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        final JPanel contentPane = new JPanel();
+        contentPane.setBorder(new EmptyBorder(0, 0, 0, 0));
+        setContentPane(contentPane);
+        contentPane.setLayout(null);
+
+        final JLabel lblDisclaimer = new JLabel("Forge is not affiliated in any way with Wizards of the Coast.");
+
+        // we can't do multiline labels.
+        //+ "\nIt is open source software, released under the GNU Public License."
+        //+ "\n And while we have your attention, go buy some Magic: the Gathering cards!"
+
+        lblDisclaimer.setBounds(DISCLAIMER_EAST_WEST_PADDING_PX, DISCLAIMER_NORTH_PADDING_PX,
+                splashWidthPx - (2 * DISCLAIMER_EAST_WEST_PADDING_PX),
+                DISCLAIMER_HEIGHT_PX);
+
+        lblDisclaimer.setFont(new Font("Tahoma", Font.PLAIN, DISCLAIMER_FONT_SIZE));
+        lblDisclaimer.setHorizontalAlignment(SwingConstants.CENTER);
+        lblDisclaimer.setForeground(WHITE_COLOR);
+        contentPane.add(lblDisclaimer);
+
+
+        // Add background image.
+        contentPane.setOpaque(false);
+        final JLabel bgLabel = new JLabel(bgIcon);
+
+        // Do not pass Integer.MIN_VALUE directly here; it must be packaged in an Integer
+        // instance.  Otherwise, GUI components will not draw unless moused over.
+        getLayeredPane().add(bgLabel, Integer.valueOf(Integer.MIN_VALUE));
+
+        bgLabel.setBounds(0, 0, bgIcon.getIconWidth(), bgIcon.getIconHeight());
+
+        pack();
+    }
+
+    /**
+     * Getter for monitor.
+     * @return the MultiPhaseProgressMonitorWithETA in the lower section of this JFrame
+     */
+    public final MultiPhaseProgressMonitorWithETA getMonitor() {
+        return monitor;
+    }
+
+    /**
+     * Setter for monitor.
+     * @param neoMonitor  the MultiPhaseProgressMonitorWithETA in the lower section of this JFrame
+     */
+    protected final void setMonitor(final MultiPhaseProgressMonitorWithETA neoMonitor) {
+        this.monitor = neoMonitor;
+    }
+}
Index: src/main/java/forge/view/FView.java
===================================================================
--- src/main/java/forge/view/FView.java   (revision 9802)
+++ src/main/java/forge/view/FView.java   (working copy)
@@ -1,5 +1,6 @@
 package forge.view;
 
+import net.slightlymagic.braids.util.progress_monitor.BraidsProgressMonitor;
 import forge.model.FModel;
 
 /**
@@ -15,4 +16,11 @@
      */
     void setModel(FModel model);
 
+    /**
+     * Get the progress monitor for loading all cards at once.
+     *
+     * @return a progress monitor having only one phase; may be null
+     */
+    BraidsProgressMonitor getCardLoadingProgressMonitor();
+
 }
Index: src/main/java/forge/view/swing/ApplicationView.java
===================================================================
--- src/main/java/forge/view/swing/ApplicationView.java   (revision 9802)
+++ src/main/java/forge/view/swing/ApplicationView.java   (working copy)
@@ -1,8 +1,12 @@
 package forge.view.swing;
 
+import java.lang.reflect.InvocationTargetException;
+
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 
+import net.slightlymagic.braids.util.progress_monitor.BraidsProgressMonitor;
+
 import com.esotericsoftware.minlog.Log;
 
 import forge.AllZone;
@@ -22,14 +26,45 @@
  * The main view for Forge: a java swing application.
  */
 public class ApplicationView implements FView {
+
+    private SplashFrame splashFrame;
+
     /**
      * Constructor.
      */
     public ApplicationView() { // NOPMD by Braids on 8/7/11 1:14 PM: Damnation if it's here; Damnation if it's not.
-        // TODO: insert splash window here
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                    splashFrame = new SplashFrame();
+                    splashFrame.setVisible(true);
     }
+            });
+        } catch (InterruptedException exn) {
+            throw new RuntimeException(exn);
+        } catch (InvocationTargetException exn) {
+            throw new RuntimeException(exn);
+        }
+    }
 
     /* (non-Javadoc)
+     * @see forge.view.FView#getCardLoadingProgressMonitor()
+     */
+    @Override
+    public final BraidsProgressMonitor getCardLoadingProgressMonitor() {
+        BraidsProgressMonitor result;
+
+        if (splashFrame == null) {
+            result = null;
+        }
+        else {
+            result = splashFrame.getMonitor();
+        }
+
+        return result;
+    }
+
+    /* (non-Javadoc)
      * @see forge.view.FView#setModel(forge.model.FModel)
      */
     @Override
@@ -73,11 +108,23 @@
             }
         });
 
+        AllZone.getCardFactory(); // forces preloading of all cards
         try {
             Constant.Runtime.GameType[0] = Constant.GameType.Constructed;
             SwingUtilities.invokeLater(new Runnable() { // NOPMD by Braids on 8/7/11 1:07 PM: this isn't a web app
                 public void run() {
                     AllZone.setComputer(new ComputerAI_Input(new ComputerAI_General()));
+
+                    getCardLoadingProgressMonitor().dispose();
+
+                    // Enable only one of the following two lines. The second
+                    // is useful for debugging.
+
+                    splashFrame.dispose();
+                    //splashFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+
+                    splashFrame = null;
                     new OldGuiNewGame();
                 }
             });
@@ -85,6 +132,5 @@
             ErrorViewer.showError(ex);
         }
 
-
     }
 }
Index: src/main/java/forge/gui/MultiPhaseProgressMonitorWithETA.java
===================================================================
--- src/main/java/forge/gui/MultiPhaseProgressMonitorWithETA.java   (revision 9802)
+++ src/main/java/forge/gui/MultiPhaseProgressMonitorWithETA.java   (working copy)
@@ -1,9 +1,13 @@
 package forge.gui;
 
+import java.lang.reflect.InvocationTargetException;
+
 import javax.swing.JDialog;
 import javax.swing.JProgressBar;
+import javax.swing.SwingUtilities;
 
 import forge.Gui_ProgressBarWindow;
+import net.slightlymagic.braids.util.UtilFunctions;
 import net.slightlymagic.braids.util.progress_monitor.BaseProgressMonitor;
 
 /**
@@ -33,6 +37,10 @@
    /**
     * Create a GUI progress monitor and open its first dialog.
     *
+    * Like all swing components, this constructor must be invoked from the
+    * swing Event Dispatching Thread. The rest of the methods of this class
+    * are exempt from this requirement.
+    *
     * @param title  the title to give the dialog box(es)
     *
     * @param numPhases  the total number of phases to expect
@@ -54,6 +62,10 @@
       super(numPhases, totalUnitsFirstPhase, minUIUpdateIntervalSec,
             phaseWeights);
       
+        if (!SwingUtilities.isEventDispatchThread()) {
+            throw new IllegalStateException("must be called from within an event dispatch thread");
+        }
+
       this.title = title;
    }
 
@@ -65,10 +77,25 @@
 
        System.out.println("Initializing...");
 
-       MultiPhaseProgressMonitorWithETA monitor =
+       // This is a trick to get an output variable from a Runnable.
+       final MultiPhaseProgressMonitorWithETA[] monitorPointer = new MultiPhaseProgressMonitorWithETA[1];
+
+       try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                   monitorPointer[0] =
           new MultiPhaseProgressMonitorWithETA("Testing 2 phases", 2, 5000,
                 1.0f, null);
+                }
+            });
+        } catch (InterruptedException exn) {
+            throw new RuntimeException(exn);
+        } catch (InvocationTargetException exn) {
+            throw new RuntimeException(exn);
+        }
        
+       MultiPhaseProgressMonitorWithETA monitor = monitorPointer[0];
+
        System.out.println("Running...");
 
        for (int i = 0; i <= 5000; i++) {
@@ -113,13 +140,15 @@
     *
     * @see net.slightlymagic.braids.util.progress_monitor.ProgressMonitor#setTotalUnitsThisPhase(long)
     */
-   public void setTotalUnitsThisPhase(long numUnits) {
+   public void setTotalUnitsThisPhase(final long numUnits) {
       super.setTotalUnitsThisPhase(numUnits);
       
       if (numUnits > Integer.MAX_VALUE) {
          throw new IllegalArgumentException("numUnits must be <= " + Integer.MAX_VALUE);
       }
 
+      final Runnable proc = new Runnable() {
+          public void run() {
       if (numUnits > 0) {
          // (Re)create the progress bar.
          if (dialog != null) {
@@ -142,7 +171,11 @@
          bar.setValue(0);   
       }
    }
+      };
    
+      UtilFunctions.invokeInEventDispatchThreadAndWait(proc);
+   }
+   
     @Override
    /**
     * @see net.slightlymagic.braids.util.progress_monitor.ProgressMonitor#incrementUnitsCompletedThisPhase(long)
@@ -151,8 +184,12 @@
       super.incrementUnitsCompletedThisPhase(numUnits);
         
         for (int i = 0 ; i < numUnits ; i++) {
+            UtilFunctions.invokeInEventDispatchThreadAndWait(new Runnable() {
+                public void run() {
            dialog.increment();
         }
+            });
+        }
 
         if (shouldUpdateUI()) {
 
@@ -187,8 +224,10 @@
      *
      * @param message  the message to display
      */
-    public void displayUpdate(String message) {
+    public void displayUpdate(final String message) {
 
+        final Runnable proc = new Runnable() {
+            public void run() {
        // i've been having trouble getting the dialog to display its title.
       dialog.setTitle(title);
 
@@ -197,12 +236,25 @@
        
         justUpdatedUI();
     }
+        };
 
+        if (SwingUtilities.isEventDispatchThread()) {
+            proc.run();
+        }
+        else {
+            SwingUtilities.invokeLater(proc);
+        }
+    }
     
+
     @Override
-    public void dispose() {
+    public final void dispose() {
+        UtilFunctions.invokeInEventDispatchThreadAndWait(new Runnable() {
+            public void run() {
        getDialog().dispose();
     }
+        });
+    }
     
 
     /**
Index: src/main/java/forge/CardReader.java
===================================================================
--- src/main/java/forge/CardReader.java   (revision 9802)
+++ src/main/java/forge/CardReader.java   (working copy)
@@ -1,16 +1,12 @@
 package forge;
 
-import com.google.code.jyield.Generator;
-import com.google.code.jyield.YieldUtils;
-import forge.card.trigger.TriggerHandler;
-import forge.error.ErrorViewer;
-import forge.gui.MultiPhaseProgressMonitorWithETA;
-import forge.properties.NewConstants;
-import net.slightlymagic.braids.util.UtilFunctions;
-import net.slightlymagic.braids.util.generator.FindNonDirectoriesSkipDotDirectoriesGenerator;
-import net.slightlymagic.braids.util.generator.GeneratorFunctions;
-
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.nio.charset.Charset;
 import java.util.Enumeration;
 import java.util.Locale;
@@ -20,7 +16,21 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import net.slightlymagic.braids.util.UtilFunctions;
+import net.slightlymagic.braids.util.generator.FindNonDirectoriesSkipDotDirectoriesGenerator;
+import net.slightlymagic.braids.util.generator.GeneratorFunctions;
+import net.slightlymagic.braids.util.progress_monitor.BraidsProgressMonitor;
+import net.slightlymagic.braids.util.progress_monitor.StderrProgressMonitor;
 
+import com.google.code.jyield.Generator;
+import com.google.code.jyield.YieldUtils;
+
+import forge.card.trigger.TriggerHandler;
+import forge.error.ErrorViewer;
+import forge.properties.NewConstants;
+import forge.view.FView;
+
+
 /**
  * <p>CardReader class.</p>
  *
@@ -165,12 +175,19 @@
     protected final Card loadCardsUntilYouFind(final String cardName) {
         Card result = null;
 
-        MultiPhaseProgressMonitorWithETA monitor;
+        BraidsProgressMonitor monitor = null;
+        final FView view = Singletons.getView();
+        if (view != null) {
+            monitor = view.getCardLoadingProgressMonitor();
+        }
 
+        if (monitor == null) {
+            monitor = new StderrProgressMonitor(1, 0L);
+        }
+
+
         if (zip != null) {
-            monitor = new MultiPhaseProgressMonitorWithETA("Forge - Loading card database from zip file", 1,
-                    estimatedFilesRemaining, 1.0f);
-
+            monitor.setTotalUnitsThisPhase(estimatedFilesRemaining);
             ZipEntry entry;
 
             // zipEnum was initialized in the constructor.
@@ -197,8 +214,7 @@
                 findNonDirsIterable = YieldUtils.toIterable(findNonDirsGen);
             }
 
-            monitor = new MultiPhaseProgressMonitorWithETA("Forge - Loading card database from files", 1,
-                    estimatedFilesRemaining, 1.0f);
+            monitor.setTotalUnitsThisPhase(estimatedFilesRemaining);
 
             for (File cardTxtFile : findNonDirsIterable) {
                 if (!cardTxtFile.getName().endsWith(".txt")) {
Index: res/images/ui/forgeSplash by moomarc.jpg
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: res/images/ui/forgeSplash by moomarc.jpg
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: src/test/java/forge/card/cardFactory/CardFactoryTest.java
===================================================================
--- src/test/java/forge/card/cardFactory/CardFactoryTest.java   (revision 9802)
+++ src/test/java/forge/card/cardFactory/CardFactoryTest.java   (working copy)
@@ -8,6 +8,7 @@
 import net.slightlymagic.braids.util.ClumsyRunnable;
 import net.slightlymagic.braids.util.testng.BraidsAssertFunctions;
 import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import java.util.Set;
@@ -24,13 +25,14 @@
 @Test(groups = {"UnitTest"}, timeOut = 5000)
 public class CardFactoryTest implements NewConstants {
 
-    private static CardFactoryInterface factory;
-    static {
+    private CardFactoryInterface factory;
+
+    @BeforeMethod
+    public final void setUp() {
         OldGuiNewGame.loadDynamicGamedata();
         factory = new LazyCardFactory(ForgeProps.getFile(CARDSFOLDER));
     }
 
-
     /**
      * Just a quick test to see if Arc-Slogger is in the database, and if it
      * has the correct owner.
@@ -44,10 +46,8 @@
 
     /**
      * Make sure the method throws an exception when it's supposed to.
-     *
-     * This doesn't work with LazyCardFactory, so it is too slow to enable by default.
      */
-    @Test(enabled = false, timeOut = 5000)
+    @Test(enabled = true, timeOut = 5000)
     public final void test_getRandomCombinationWithoutRepetition_tooLarge() {
         BraidsAssertFunctions.assertThrowsException(IllegalArgumentException.class,
                 new ClumsyRunnable() {
@@ -72,6 +72,7 @@
      */
     @Test(enabled = false, timeOut = 5000)
     public final void test_getRandomCombinationWithoutRepetition_oneTenth() {
+        factory = new PreloadingCardFactory(ForgeProps.getFile(CARDSFOLDER));
         int divisor = 10;
         final CardList actual = factory.getRandomCombinationWithoutRepetition(factory.size() / divisor);
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Aug 2011 GUI Overhaul

Postby Snacko » 18 Aug 2011, 11:32

SplashFrame constructor accesses swing methods and creates swing objects so all of this has to be moved to Swing dispatch thread. You run under the assumption that everyone will remember to run your object on sdt (objects should be self contained). Also never ever use invokeAndWait as it's a bad practice to use blocking IO (you should design it to run as invokeLater).
To get output form Runnable, please use SwingWorker as it has all you need.
Snacko
DEVELOPER
 
Posts: 826
Joined: 29 May 2008, 19:35
Has thanked: 4 times
Been thanked: 74 times

Re: Aug 2011 GUI Overhaul

Postby Braids » 18 Aug 2011, 14:39

thanks for looking at my code, Snacko!

Snacko wrote:SplashFrame constructor accesses swing methods and creates swing objects so all of this has to be moved to Swing dispatch thread. You run under the assumption that everyone will remember to run your object on sdt (objects should be self contained).
SplashFrame constructor now throws IllegalStateException if it is not called from the event dispatch thread.

Snacko wrote:Also never ever use invokeAndWait as it's a bad practice to use blocking IO (you should design it to run as invokeLater).
i have reduced all uses except one to invokeLater. part of the ApplicationView constructor's contract is that the splashFrame field has been initialized before the constructor exits. i placed splashFrame's construction in an invokeAndWait and splashFrame.setVisible in an invokeLater. i could have avoided this by requiring that ApplicationView be called from an event dispatch thread, but i wanted the class to be more "self contained".

Snacko wrote:To get output form Runnable, please use SwingWorker as it has all you need.
i wasn't able to find anything in SwingWorker to help with getting output from a Runnable, so i just placed everything in MultiPhaseProgressMonitorWithETA.main inside an invokeLater. besides, that main method is just a quick method for testing. it is never called from the normal Forge application.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Aug 2011 GUI Overhaul

Postby Braids » 19 Aug 2011, 03:59

i've committed the splash screen (frame) changes to r9809. i cleaned up the code in a separate commit, r9810. for conformance with our 3 code checking tools. the separate commits help to distinguish semantic changes from housekeeping.

edit: i have relinquished assignment of Mantis issue 106. i trust someone else would be interested in placing the progress bar inside the splash frame.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Aug 2011 GUI Overhaul

Postby Rob Cashwalker » 19 Aug 2011, 14:36

Thanks Braids. It's not critical that the bar be integrated into the splash screen. It gets the job done, as they say. At least it's clear to the user that Forge is running and it's doing something.

How 'bout we just declare it closed?
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: Aug 2011 GUI Overhaul

Postby Braids » 19 Aug 2011, 15:41

if you want to close it, that's ok. someone can move the progress bar later, or trim the bottom part out of the splash image.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Aug 2011 GUI Overhaul

Postby moomarc » 19 Aug 2011, 17:35

Braids wrote:if you want to close it, that's ok. someone can move the progress bar later, or trim the bottom part out of the splash image.
I'll trim the artwork if you want. Or would you prefer me to adjust the artwork to either fill the area better, or just adjust the border trim to allow for more disclaimer/info text (I seem to recall Braids saying she couldn't fit much text in there) =D> Well done on the splash!
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Aug 2011 GUI Overhaul

Postby Braids » 19 Aug 2011, 17:55

moomarc wrote:
Braids wrote:if you want to close it, that's ok. someone can move the progress bar later, or trim the bottom part out of the splash image.
I'll trim the artwork if you want. Or would you prefer me to adjust the artwork to either fill the area better, or just adjust the border trim to allow for more disclaimer/info text (I seem to recall Braids saying she couldn't fit much text in there) =D> Well done on the splash!
i like the idea of using the bottom rectangle for more text. perhaps we can get an undecorated TextArea in there without scrollbars, etc. for multiple lines.

edit: oh, and thank you. it has been a while since i used swing.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Splash missed beta

Postby Braids » 19 Aug 2011, 19:13

i'm sorry the splash image didn't make it into the recent beta. i added but forgot to commit the image. :oops: at least it starts up ok without it!
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Splash missed beta

Postby moomarc » 20 Aug 2011, 07:15

Braids wrote:i'm sorry the splash image didn't make it into the recent beta. i added but forgot to commit the image. :oops: at least it starts up ok without it!
No problem. This way more attention was drawn to it and it was attributed to me, so more people know I did the artwork now. :mrgreen: Maybe I should insist a link to my website be include as punishment though :twisted: Mwahaha!!
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

Re: Aug 2011 GUI Overhaul

Postby Chris H. » 20 Aug 2011, 10:07

I added a link in the beta topic to an archive with the pic. People are downloading it. I like the splash screen, good job Marc.
User avatar
Chris H.
Forge Moderator
 
Posts: 6320
Joined: 04 Nov 2008, 12:11
Location: Mac OS X Yosemite
Has thanked: 644 times
Been thanked: 643 times

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 26 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 26 users online :: 0 registered, 0 hidden and 26 guests (based on users active over the past 10 minutes)
Most users ever online was 7303 on 15 Jul 2025, 20:46

Users browsing this forum: No registered users and 26 guests

Login Form