src/chat/ChatDemo.java
author Matthias Mann
Fri Feb 03 06:35:38 2012 +0100 (2 days ago)
changeset 260 42064e048ff4
parent 214 fb8d23854f43
permissions -rw-r--r--
LoginDemo: added initial keyboard focus, edit fields respond to return key
     1 /*
     2  * Copyright (c) 2008-2010, Matthias Mann
     3  *
     4  * All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *     * Redistributions of source code must retain the above copyright notice,
    10  *       this list of conditions and the following disclaimer.
    11  *     * Redistributions in binary form must reproduce the above copyright
    12  *       notice, this list of conditions and the following disclaimer in the
    13  *       documentation and/or other materials provided with the distribution.
    14  *     * Neither the name of Matthias Mann nor the names of its contributors may
    15  *       be used to endorse or promote products derived from this software
    16  *       without specific prior written permission.
    17  *
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29  */
    30 package chat;
    31 
    32 import de.matthiasmann.twl.DesktopArea;
    33 import de.matthiasmann.twl.DialogLayout;
    34 import de.matthiasmann.twl.EditField;
    35 import de.matthiasmann.twl.Event;
    36 import de.matthiasmann.twl.FPSCounter;
    37 import de.matthiasmann.twl.GUI;
    38 import de.matthiasmann.twl.ResizableFrame;
    39 import de.matthiasmann.twl.ScrollPane;
    40 import de.matthiasmann.twl.TextArea;
    41 import de.matthiasmann.twl.textarea.HTMLTextAreaModel;
    42 import de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer;
    43 import de.matthiasmann.twl.theme.ThemeManager;
    44 import org.lwjgl.Sys;
    45 import org.lwjgl.opengl.Display;
    46 import org.lwjgl.opengl.DisplayMode;
    47 import org.lwjgl.opengl.GL11;
    48 import test.TestUtils;
    49 
    50 /**
    51  * A chat demo
    52  *
    53  * This class also acts as root pane
    54  *
    55  * @author Matthias Mann
    56  */
    57 public class ChatDemo extends DesktopArea {
    58 
    59     public static void main(String[] args) {
    60         try {
    61             Display.setDisplayMode(new DisplayMode(800, 600));
    62             Display.create();
    63             Display.setTitle("TWL Chat Demo");
    64             Display.setVSyncEnabled(true);
    65 
    66             LWJGLRenderer renderer = new LWJGLRenderer();
    67             ChatDemo chat = new ChatDemo();
    68             GUI gui = new GUI(chat, renderer);
    69 
    70             ThemeManager theme = ThemeManager.createThemeManager(
    71                     ChatDemo.class.getResource("chat.xml"), renderer);
    72             gui.applyTheme(theme);
    73 
    74             while(!Display.isCloseRequested() && !chat.quit) {
    75                 GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
    76 
    77                 gui.update();
    78                 Display.update();
    79                 TestUtils.reduceInputLag();
    80             }
    81 
    82             gui.destroy();
    83             theme.destroy();
    84         } catch (Exception ex) {
    85             TestUtils.showErrMsg(ex);
    86         }
    87         Display.destroy();
    88     }
    89 
    90     private final FPSCounter fpsCounter;
    91     private final ChatFrame chatFrame;
    92 
    93     public boolean quit;
    94 
    95     public ChatDemo() {
    96         fpsCounter = new FPSCounter();
    97         add(fpsCounter);
    98 
    99         chatFrame = new ChatFrame();
   100         add(chatFrame);
   101 
   102         chatFrame.setSize(400, 200);
   103         chatFrame.setPosition(10, 350);
   104     }
   105 
   106     @Override
   107     protected void layout() {
   108         super.layout();
   109 
   110         // fpsCounter is bottom right
   111         fpsCounter.adjustSize();
   112         fpsCounter.setPosition(
   113                 getInnerWidth() - fpsCounter.getWidth(),
   114                 getInnerHeight() - fpsCounter.getHeight());
   115     }
   116 
   117     @Override
   118     protected boolean handleEvent(Event evt) {
   119         if(super.handleEvent(evt)) {
   120             return true;
   121         }
   122         switch (evt.getType()) {
   123             case KEY_PRESSED:
   124                 switch (evt.getKeyCode()) {
   125                     case Event.KEY_ESCAPE:
   126                         quit = true;
   127                         return true;
   128                 }
   129         }
   130         return false;
   131     }
   132 
   133     static class ChatFrame extends ResizableFrame {
   134         private final StringBuilder sb;
   135         private final HTMLTextAreaModel textAreaModel;
   136         private final TextArea textArea;
   137         private final EditField editField;
   138         private final ScrollPane scrollPane;
   139         private int curColor;
   140 
   141         public ChatFrame() {
   142             setTitle("Chat");
   143 
   144             this.sb = new StringBuilder();
   145             this.textAreaModel = new HTMLTextAreaModel();
   146             this.textArea = new TextArea(textAreaModel);
   147             this.editField = new EditField();
   148 
   149             editField.addCallback(new EditField.Callback() {
   150                 public void callback(int key) {
   151                     if(key == Event.KEY_RETURN) {
   152                         // cycle through 3 different colors/font styles
   153                         appendRow("color"+curColor, editField.getText());
   154                         editField.setText("");
   155                         curColor = (curColor + 1) % 3;
   156                     }
   157                 }
   158             });
   159 
   160             textArea.addCallback(new TextArea.Callback() {
   161                 public void handleLinkClicked(String href) {
   162                     Sys.openURL(href);
   163                 }
   164             });
   165 
   166             scrollPane = new ScrollPane(textArea);
   167             scrollPane.setFixed(ScrollPane.Fixed.HORIZONTAL);
   168 
   169             DialogLayout l = new DialogLayout();
   170             l.setTheme("content");
   171             l.setHorizontalGroup(l.createParallelGroup(scrollPane, editField));
   172             l.setVerticalGroup(l.createSequentialGroup(scrollPane, editField));
   173 
   174             add(l);
   175 
   176             appendRow("default", "Welcome to the chat demo. Type your messages below :)");
   177         }
   178 
   179         private void appendRow(String font, String text) {
   180             sb.append("<div style=\"word-wrap: break-word; font-family: ").append(font).append("; \">");
   181             // not efficient but simple
   182             for(int i=0,l=text.length() ; i<l ; i++) {
   183                 char ch = text.charAt(i);
   184                 switch(ch) {
   185                     case '<': sb.append("&lt;"); break;
   186                     case '>': sb.append("&gt;"); break;
   187                     case '&': sb.append("&amp;"); break;
   188                     case '"': sb.append("&quot;"); break;
   189                     case ':':
   190                         if(text.startsWith(":)", i)) {
   191                             sb.append("<img src=\"smiley\" alt=\":)\"/>");
   192                             i += 1; // skip one less because of i++ in the for loop
   193                             break;
   194                         }
   195                         sb.append(ch);
   196                         break;
   197                     case 'h':
   198                         if(text.startsWith("http://", i)) {
   199                             int end = i + 7;
   200                             while(end < l && isURLChar(text.charAt(end))) {
   201                                 end++;
   202                             }
   203                             String href = text.substring(i, end);
   204                             sb.append("<a style=\"font: link\" href=\"").append(href)
   205                                     .append("\" >").append(href)
   206                                     .append("</a>");
   207                             i = end - 1; // skip one less because of i++ in the for loop
   208                             break;
   209                         }
   210                         // fall through:
   211                     default:
   212                         sb.append(ch);
   213                 }
   214             }
   215             sb.append("</div>");
   216 
   217             boolean isAtEnd = scrollPane.getMaxScrollPosY() == scrollPane.getScrollPositionY();
   218 
   219             textAreaModel.setHtml(sb.toString());
   220 
   221             if(isAtEnd) {
   222                 scrollPane.validateLayout();
   223                 scrollPane.setScrollPositionY(scrollPane.getMaxScrollPosY());
   224             }
   225         }
   226 
   227         private boolean isURLChar(char ch) {
   228             return (ch == '.') || (ch == '/') || (ch == '%') ||
   229                     (ch >= '0' && ch <= '9') ||
   230                     (ch >= 'a' && ch <= 'z') ||
   231                     (ch >= 'A' && ch <= 'Z');
   232         }
   233     }
   234 }