Community
Participate
Working Groups
Wasn't a requirement, but McQ feels it should be on the new features list. Low priority at this point. NOTES: CM (10/2/2001 1:53:32 PM) Also: 1G9X6KJ: SWT:WIN2000 - Word wrapping does not work in StyledWidget CM (10/2/2001 1:53:38 PM) From Eclipse Corner: From: "Sharon" <sharon_dagan@il.ibm.com> Newsgroups: eclipse.tools Sent: Tuesday, September 18, 2001 6:21 PM Subject: Can StyledText widget wrap lines? > I've noticed that StyledText cannot wrap lines - if this is indeed the > case, I'd like to make that into a feature request. > > -Sharon I guess users are starting to ask for this. The work to do word wrap was done for printing. Not sure how hard it would be to translate that over to having a WORD_WRAP style for the widget...
We should investigate doing this to see what it will take.
In our product, we use the SourceViewer (StyledText widget) to edit/view SQL statements. We use the SourceViewer for the syntax highlighting and code assist support. A SourceViewer is used to display individual SQL clauses for a SQL statement. There can be anywhere from 1 to 5 clauses per statement. Each clause editor uses a SourceViewer. In the screen capture below is an example of a statement with 5 clause editors. We have to have individual clause editors because we support non-standard SQL. If the user were to enter his entire statement in one editor, we wouldn't be able to parse it back out to the individual clauses because of this non-standard support. The example below is very simplistic. Our customers in reality have very long clauses. By default, we build clauses for our customers based on records that are built from their SQL table(s). They can have 1..many columns in their table so the clauses that we build for them can be very long. Sometimes we add tabs and carriage return line feeds but for the most part the clauses are one long text string. We would like the viewer that we are using to wrap the text based on the size of the viewer. As you can see, there is not much screen real estate so we don't want to add horizontal scroll bars to each clause editor and we don't want our users to have to scroll to horizontally to see their data. This is why it is very important for us to have the StyledText widget wrap lines. We would like to see the priority for this PR changed from a 3 to a 2.
Function ======== Split lines after spaces (i.e., wrap words). If the last remaining word on the line does not fit entirely wrap character based, i.e. split the word. General Concepts ================ ContentWidthCache: Can be used to wrap lines. Wherever ContentWidthCache.calculate is called the line wrapping needs to be recalculated. Note: During resize all wrapped lines need to be reset and those that are visible need to be recalculated. This is different from the normal use where lines are only reset when they (or their styles) have changed. StyledTextContent: Create a wrapper that works with visual line indices. getOffsetAtLine(visualLine) visualLine getLineAtOffset() String getLine(visualLine) numVisualLines getLineCount() Note that the original, wrapped, StyledTextContent still needs to be accessible for use by StyledText API (e.g., getLineCount). Changes to StyledText ===================== (ok) means that something is trivial or needs no change to support word wrap. API methods should eventually lead to one of the internal methods. Internal Methods ---------------- computeSize: Compute preferred size to show as many wrapped lines as possible. Maximum width == screen width followed by maximum height == screen height. handlePaint: topIndex is visual, content wrapper returns visual lines for visual indices handlePaint->drawLine->getLineBackgroundData: Called with visual offset & line. same as getLineStyleData below handlePaint->drawLine->drawLineSelectionBackground: Change line break selection showBidiCaret: Ok if content.getLineAtOffset/content.getOffsetAtLine return data based on visual (wrapped) lines. Will create a bidi object using the wrapped line. showBidiCaret->showLocation: Ok when called with visual line indices and assuming that the top index and bottom index represent visual lines. showBidiCaret->setBidiCaretLocation: Similar to showBidiCaret. showCaret->getXAtOffset->textWidth->getLineStyleData: Called with visual line data, needs to send an event using logical line. I.e., needs to convert lineOffset, lineText back to logical. Also needs to (should, really - we may work with leaving bogus styles in the visual line) chop off styles that aren't on the requested visual line. showCaret->setCaretLocation: Ok, gets called with visual line API Methods ----------- No op: getHorizontalIndex (return 0), getHorizontalPixel (return 0), setHorizontalIndex getLineAtOffset Return logical line getLineBackground Return logical line getLocationAtOffset Change to use visual line. getOffsetAtLocation->getOffsetAtX->getLineStyleData: See textWidth above. redraw (ok) redrawRange->internalRedrawRange (ok) replaceTextRange->handleTextChanging: change redraw replaceTextRange->handleTextChanged->claimBottomFreeSpace- >setVerticalScrollOffset (ok) setText->handleTextSet->reset ->calculateContentWidth: calculate line wrap, interact with StyledTextContent wrapper ->handlePaint (s.a.) showSelection->showOffset: ->getXAtOffset->textWidth (s.a.) ->showLocation (s.a.)
Created attachment 167 [details] Same as comment from 2001-12-11 17:56. May be easier to read and update.
Keyboard navigation: We solely rely on the caret offset to position the caret on a line in the document. This presents a problem in word wrap mode because the end offset of a visual line is the same as the start offset of the next visual line. Therefore, when the caret is at the end of a visual line/start of the next visual line the usual content.getLineAtOffset can not be used to determine the actual visual line the caret is on. Likewise, the caret positioning code does not have enough information to place the caret on the correct visual line. There are a few options to deal with this while only introducing localized code changes: 1. Pass the desired line to showCaret: The desired line is unknown in the line change example because moving down one line from the end of visual line 0 (e.g., offset 2) is the same as moving down one line from the start of visual line 1 (e.g., offset 2). A fix would be to compare the caret position. However this would need to be done for the line change case and for the line start/end case. 2. Passing the previous caret offset to showCaret: This does not help because moving to the line end from offset 0 results in the same state as moving one line down from offset 0. Yet, the desired line is 0 in the first case and 1 in the line down case. 3. Use the caret pixel location to determine the desired line: The caret location would need to be checked in many navigation methods and then the desired line would need to be passed to showCaret. In addition mouse caret position changes would have to handled differently because they do not call showCaret. Another option is to store the caret line index in addition to the caret offset. This does require a new field but is otherwise straightforward with the least amount of code changes in the navigation methods. Whenever the caret offset is changed the desired caret line is known or can be calculated using the previous caret line. The caret line can then be used in showCaret and setCaretLocation to override the line returned by content.getLineAtOffset. The required code changes are fairly localized. There's a small risk to this change in that the caret line may not be set correctly. However, this shouldn't be a problem with sufficient testing.
Enabling word wrap during widget startup: Currently, when word wrap is enabled while the widget hierarchy is being initialized (i.e., the client area width is 0) all lines are wrapped to the first character only to be rewrapped to the client area width when the widget is first made visible. There has to be *some* initial state because the WrappedContent has to answer valid values for the implemented StyledTextContent API. We could deal with this by testing whether the client area width is 0 and if it is forward all StyledTextContent API calls to the real (logical) StyledTextContent implementor. This would mean that the initial state is "infinite client area width".
Changed setTopIndex/getTopIndex to take/answer the logical line index. If there is more than one visual line at a logical line index the first visual line (i.e., the first of a series of wrapped lines) is made the top line.
Preferred Size in Word Wrap Mode ================================ StyledText.computeSize now wraps lines based on the specified width hint or the StyledText.DEFAULT_WIDTH if no hint is specified. The resulting number of lines is the preferred height unless a height hint is specified or the widget is in SINGLE line mode.
Released word wrap support into HEAD. Use the SWT.WRAP creation style or the new setWordWrap API to activate. We did not do a performance pass. The resize performance is a little slow when word wrap is on and a large number of lines are wrapped. Resize is very slow on bidi platforms (Hebrew, Arabic) in the same scenario. One optimization to speed up resizing the widget smaller would be to store not only the length of a line but also its width. We could then compare the line width against the new wrap width and skip lines that still fit. This would improve the performance when only a few lines actually need rewrapping based on a new, smaller widget width.