+++ /dev/null
-/*
- * Jexer - Java Text User Interface
- *
- * The MIT License (MIT)
- *
- * Copyright (C) 2019 Kevin Lamonte
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * @author Kevin Lamonte [kevin.lamonte@gmail.com]
- * @version 1
- */
-package jexer.help;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import jexer.THelpWindow;
-import jexer.TScrollableWidget;
-import jexer.TVScroller;
-import jexer.TWidget;
-import jexer.bits.CellAttributes;
-import jexer.bits.StringUtils;
-import jexer.event.TKeypressEvent;
-import jexer.event.TMouseEvent;
-import static jexer.TKeypress.*;
-
-/**
- * THelpText displays help text with clickable links in a scrollable text
- * area. It reflows automatically on resize.
- */
-public class THelpText extends TScrollableWidget {
-
- // ------------------------------------------------------------------------
- // Constants --------------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * The number of lines to scroll on mouse wheel up/down.
- */
- private static final int wheelScrollSize = 3;
-
- // ------------------------------------------------------------------------
- // Variables --------------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * The paragraphs in this text box.
- */
- private List<TParagraph> paragraphs;
-
- // ------------------------------------------------------------------------
- // Constructors -----------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * Public constructor.
- *
- * @param parent parent widget
- * @param topic the topic to display
- * @param x column relative to parent
- * @param y row relative to parent
- * @param width width of text area
- * @param height height of text area
- */
- public THelpText(final THelpWindow parent, final Topic topic, final int x,
- final int y, final int width, final int height) {
-
- // Set parent and window
- super(parent, x, y, width, height);
-
- vScroller = new TVScroller(this, getWidth() - 1, 0,
- Math.max(1, getHeight()));
-
- setTopic(topic);
- }
-
- // ------------------------------------------------------------------------
- // TScrollableWidget ------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * Override TWidget's width: we need to set child widget widths.
- *
- * @param width new widget width
- */
- @Override
- public void setWidth(final int width) {
- super.setWidth(width);
- if (hScroller != null) {
- hScroller.setWidth(getWidth() - 1);
- }
- if (vScroller != null) {
- vScroller.setX(getWidth() - 1);
- }
- }
-
- /**
- * Override TWidget's height: we need to set child widget heights.
- * time.
- *
- * @param height new widget height
- */
- @Override
- public void setHeight(final int height) {
- super.setHeight(height);
- if (hScroller != null) {
- hScroller.setY(getHeight() - 1);
- }
- if (vScroller != null) {
- vScroller.setHeight(Math.max(1, getHeight()));
- }
- }
-
- /**
- * Handle mouse press events.
- *
- * @param mouse mouse button press event
- */
- @Override
- public void onMouseDown(final TMouseEvent mouse) {
- // Pass to children
- super.onMouseDown(mouse);
-
- if (mouse.isMouseWheelUp()) {
- for (int i = 0; i < wheelScrollSize; i++) {
- vScroller.decrement();
- }
- reflowData();
- return;
- }
- if (mouse.isMouseWheelDown()) {
- for (int i = 0; i < wheelScrollSize; i++) {
- vScroller.increment();
- }
- reflowData();
- return;
- }
-
- // User clicked on a paragraph, update the scrollbar accordingly.
- for (int i = 0; i < paragraphs.size(); i++) {
- if (paragraphs.get(i).isActive()) {
- setVerticalValue(i);
- return;
- }
- }
- }
-
- /**
- * Handle keystrokes.
- *
- * @param keypress keystroke event
- */
- @Override
- public void onKeypress(final TKeypressEvent keypress) {
- if (keypress.equals(kbTab)) {
- getParent().switchWidget(true);
- } else if (keypress.equals(kbShiftTab)) {
- getParent().switchWidget(false);
- } else if (keypress.equals(kbUp)) {
- if (!paragraphs.get(getVerticalValue()).up()) {
- vScroller.decrement();
- reflowData();
- }
- } else if (keypress.equals(kbDown)) {
- if (!paragraphs.get(getVerticalValue()).down()) {
- vScroller.increment();
- reflowData();
- }
- } else if (keypress.equals(kbPgUp)) {
- vScroller.bigDecrement();
- reflowData();
- } else if (keypress.equals(kbPgDn)) {
- vScroller.bigIncrement();
- reflowData();
- } else if (keypress.equals(kbHome)) {
- vScroller.toTop();
- reflowData();
- } else if (keypress.equals(kbEnd)) {
- vScroller.toBottom();
- reflowData();
- } else {
- // Pass other keys on
- super.onKeypress(keypress);
- }
- }
-
- /**
- * Place the scrollbars on the edge of this widget, and adjust bigChange
- * to match the new size. This is called by onResize().
- */
- protected void placeScrollbars() {
- if (hScroller != null) {
- hScroller.setY(getHeight() - 1);
- hScroller.setWidth(getWidth() - 1);
- hScroller.setBigChange(getWidth() - 1);
- }
- if (vScroller != null) {
- vScroller.setX(getWidth() - 1);
- vScroller.setHeight(getHeight());
- vScroller.setBigChange(getHeight());
- }
- }
-
- /**
- * Resize text and scrollbars for a new width/height.
- */
- @Override
- public void reflowData() {
- for (TParagraph paragraph: paragraphs) {
- paragraph.setWidth(getWidth() - 1);
- paragraph.reflowData();
- }
-
- int top = getVerticalValue();
- int paragraphsHeight = 0;
- for (TParagraph paragraph: paragraphs) {
- paragraphsHeight += paragraph.getHeight();
- }
- if (paragraphsHeight <= getHeight()) {
- // All paragraphs fit in the window.
- int y = 0;
- for (int i = 0; i < paragraphs.size(); i++) {
- paragraphs.get(i).setEnabled(true);
- paragraphs.get(i).setVisible(true);
- paragraphs.get(i).setY(y);
- y += paragraphs.get(i).getHeight();
- }
- activate(paragraphs.get(getVerticalValue()));
- return;
- }
-
- /*
- * Some paragraphs will not fit in the window. Find the number of
- * rows needed to display from the current vertical position to the
- * end:
- *
- * - If this meets or exceeds the available height, then draw from
- * the vertical position to the number of visible rows.
- *
- * - If this is less than the available height, back up until
- * meeting/exceeding the height, and draw from there to the end.
- *
- */
- int rowsNeeded = 0;
- for (int i = getVerticalValue(); i <= getBottomValue(); i++) {
- rowsNeeded += paragraphs.get(i).getHeight();
- }
- while (rowsNeeded < getHeight()) {
- // Decrease top until we meet/exceed the visible display.
- if (top == getTopValue()) {
- break;
- }
- top--;
- rowsNeeded += paragraphs.get(top).getHeight();
- }
-
- // All set, now disable all paragraphs except the visible ones.
- for (TParagraph paragraph: paragraphs) {
- paragraph.setEnabled(false);
- paragraph.setVisible(false);
- paragraph.setY(-1);
- }
- int y = 0;
- for (int i = top; (i <= getBottomValue()) && (y < getHeight()); i++) {
- paragraphs.get(i).setEnabled(true);
- paragraphs.get(i).setVisible(true);
- paragraphs.get(i).setY(y);
- y += paragraphs.get(i).getHeight();
- }
- activate(paragraphs.get(getVerticalValue()));
- }
-
- /**
- * Draw the text box.
- */
- @Override
- public void draw() {
- // Setup my color
- CellAttributes color = getTheme().getColor("thelpwindow.text");
- for (int y = 0; y < getHeight(); y++) {
- hLineXY(0, y, getWidth(), ' ', color);
- }
- }
-
- // ------------------------------------------------------------------------
- // THelpText --------------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * Set the topic.
- *
- * @param topic new topic to display
- */
- public void setTopic(final Topic topic) {
- setTopic(topic, true);
- }
-
- /**
- * Set the topic.
- *
- * @param topic new topic to display
- * @param separator if true, separate paragraphs
- */
- public void setTopic(final Topic topic, final boolean separator) {
-
- if (paragraphs != null) {
- getChildren().removeAll(paragraphs);
- }
- paragraphs = new ArrayList<TParagraph>();
-
- // Add title paragraph at top. We explicitly set the separator to
- // false to achieve the underscore effect.
- List<TWord> title = new ArrayList<TWord>();
- title.add(new TWord(topic.getTitle(), null));
- TParagraph titleParagraph = new TParagraph(this, title);
- titleParagraph.separator = false;
- paragraphs.add(titleParagraph);
- title = new ArrayList<TWord>();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < topic.getTitle().length(); i++) {
- sb.append('\u2580');
- }
- title.add(new TWord(sb.toString(), null));
- titleParagraph = new TParagraph(this, title);
- paragraphs.add(titleParagraph);
-
- // Now add the actual text as paragraphs.
- int wordIndex = 0;
-
- // Break up text into paragraphs
- String [] blocks = topic.getText().split("\n\n");
- for (String block: blocks) {
- List<TWord> words = new ArrayList<TWord>();
- String [] lines = block.split("\n");
- for (String line: lines) {
- line = line.trim();
- // System.err.println("line: " + line);
- String [] wordTokens = line.split("\\s+");
- for (int i = 0; i < wordTokens.length; i++) {
- String wordStr = wordTokens[i].trim();
- Link wordLink = null;
- for (Link link: topic.getLinks()) {
- if ((i + wordIndex >= link.getIndex())
- && (i + wordIndex < link.getIndex() + link.getWordCount())
- ) {
- // This word is part of a link.
- wordLink = link;
- wordStr = link.getText();
- i += link.getWordCount() - 1;
- break;
- }
- }
- TWord word = new TWord(wordStr, wordLink);
- /*
- System.err.println("add word at " + (i + wordIndex) + " : "
- + wordStr + " " + wordLink);
- */
- words.add(word);
- } // for (int i = 0; i < words.length; i++)
- wordIndex += wordTokens.length;
- } // for (String line: lines)
- TParagraph paragraph = new TParagraph(this, words);
- paragraph.separator = separator;
- paragraphs.add(paragraph);
- } // for (String block: blocks)
-
- setBottomValue(paragraphs.size() - 1);
- setVerticalValue(0);
- reflowData();
- }
-
-}