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