I am calling com.google.gwt.user.client.ui.TextArea.setText(myText) to set the content. After that I call setCursorPosition(myText.length()) to get the cursor to the end. This works well.
When myText has more lines then the text area can display at once, it shows a scroll bar. But it does not scroll to the cursor position. Even worse - it scrolls to the top.
How can I scroll the GWT TextArea to the cursor position? I realy need the cursor position, not the bottom of the TextArea. A JSNI workaround would be ok too.
Try adding this after setting the cursor position:
textAreaToScroll.getElement().setScrollTop(textAreaToScroll.getElement().getScrollHeight());
This will scroll the element to the bottom.
EDIT:
To scroll to the any cursor position there is (as far as I know) no easy way to do so. I don't think there is any way to ask the browser wich line the cursor is on.
I just got an idea for something that may work (haven't actually tested it) to guess a rough estimate of how long to scroll.
int cursorPos = textAreaToScroll.getCursorPos();
long offsetRatio = cursorPos / textAreaToScroll.getText().length();
//gives 0.0 to 1.0
offsetRatio += someMagicNumber; // -0.1 maybe?
// Depending on the font you may need to adjust the magic number
// to adjust the ratio if it scrolls to far or to short.
offsetRatio = offsetRatio>0.0 ? offsetRatio : 0; //make sure
//we don't get negative ratios
//(negative values may crash some browsers while others ignore it)
textAreaToScroll.getElement().setScrollTop(
textAreaToScroll.getElement().getScrollHeight() * offsetRatio );
This may scroll the roughly the desired distance. Note, this assumes each line is filled about the same amount since it uses the cursor position divided by the length of the text and not the number of lines (wich is hard to calculate). Manual newlines will skew this estimate, and proportional fonts will allso make it less accurate.
You'll probably need to adjust the ratio so that it scrolls sligtly too short rather than too far since the cursor will still be visible if it's slightly below the top of the text area.
As I said I haven't actually tested this, I may have inverted the logic and other subtle bugs.
I had a scenario where the textarea will already have something and when a new command is submitted it will add the data to it and scroll to the start of the newly added data. this is what I did
// Hold the previous height to set the scroll.
final int prevHeight = document.get().getElementById(textareadid).getScrollHeight();
// Hold the prev position if output area already has some data.
final int prevPos = this.textArea.getValue() != null ?
this.textArea.getValue().length() : 0;
after processing and setting the new data
int posCount = 0;
if (previousResponse != null && !previousResponse.isEmpty())
{
final String dataStr = "new data from process";
// add 15 lines for the cursor position
posCount = getRelativeCount(dataStr);
}
this.textArea.getElement().setScrollTop(prevHeight);
this.textArea.setCursorPos(prevPos + posCount);
private int getRelativeCount(final String str)
{
int charCount = 0;
if (str != null)
{
int NUM_ROWS = 15;
if (getUserAgent().contains("msie"))
{
NUM_ROWS = 16;
}
final String[] splitArr = str.split("\n"); // split on the new line
// char
for (int index = 0; index < splitArr.length && index < NUM_ROWS; index++)
{
charCount += splitArr[index].length();
}
}
return charCount;
}
To improve on Stein's answer, you can count the number of lines in the text, and then set the top position based on the desired line over the total lines, rather than using characters.
While you are counting lines, you will also have to determine which line the cursor is in.
String text = textArea.getText();
int lines = 1;
int pos = 0;
int cursorPos = ...;
int cursorLine = -1;
while((pos = 1+text.indexOf("\n", pos)) > 0)
{
if (cursorLine == -1 && pos > cursorPos)
cursorLine = lines;
lines++;
}
if (lines > 0 && cursorLine > 0 && cursorLine < lines)
{
int scroll = textArea.getElement().getScrollHeight();
scroll *= cursorLine;
scroll /= lines;
scroll -= 30; // Back up a bit so it's not right at the top
if (scroll < 0)
scroll = 0;
textArea.getElement().setScrollTop(scroll);
}
this worked for me:
GWT textArea Scroll issue
http://www.gwtplayground.com/2012/08/gwt-textarea-scroll-issue_21.html
Related
I've been trying to implement an infinite background animation, which should change between 4 images of equal height and then repeat the sequence. However, it does not seem to work properly.
Note anchorPoint = CGPoint(x: 0.5, y: 0)
func updateBackground(currentTime: TimeInterval){
var delta: CGFloat = 0.0
if lastUpdate != nil {
delta = CGFloat(currentTime - lastUpdate)
}
//First increment position
activeBackground1.position.y += delta*backgroundVelocity
activeBackground2.position.y += delta*backgroundVelocity
//Detect bounds surpass
if activeBackground1.position.y > activeBackground1.size.height + screen.height/2 {
lastSky = (lastSky + 1)%4
sky1 = SKTexture(imageNamed: "sky" + String(lastSky))
activeBackground1.texture = sky1
//Reposition: background1 new position is equal to minus the entire height of
//background2 + its y size.
activeBackground1.position.y = -abs(activeBackground2.size.height-activeBackground2.position.y)
}
if activeBackground2.position.y > activeBackground2.size.height + screen.height/2 {
lastSky = (lastSky + 1)%4
sky1 = SKTexture(imageNamed: "sky" + String(lastSky))
activeBackground2.texture = sky1
activeBackground2.position.y = -abs(activeBackground1.size.height-activeBackground1.position.y)
}
}
The update algorithm works fine, but when it is needed to reposition one of the two background, it seems there is an offset of about 10.0 CGFloat from one background to another. What am I doing wrong?
EDIT: It turned out that the error was located in my image, which presented some blank rows and therefore generated visualisation glitches. So my code works perfectly.
I do the test and most likely you should use something like:
activeBackground2.position.y = activeBackground1.size.height + activeBackground1.position.y
instead of
activeBackground2.position.y = -abs(activeBackground1.size.height-activeBackground1.position.y)
I did this example and it works correctly: https://github.com/Maetschl/SpriteKitExamples/tree/master/InfiniteBackground/InfiniteBackground
Feel free to see and use.
Your problem is floating point math causing rounding errors. I am on a phone right now so I can’t wrote code, but what you want to do is have 1 parent SKNode to handle your entire background.
Add your background slivers to the parent node.
You then place the moving action on the parent only.
As each sliver leaves the screen, you take the sliver, and move it to the end of the other slivers.
This jumping should always be done with integer math, leaving no holes.
Basically:
The floating point moving math is done on the parent node.
The integer based tile jumping is done on each of the slivers.
I have a problem. I using iTextSharp v. (5.5.3 to 5.5.6).
I have one file PDF and 1 page.
On the side I have 4 TextField (rotation: 0, 90, 180, 270) and one red polygon
My page rotation is set 270
I can flatten page
In code, I set
stamper.AnnotationFlattening = true;
stamper.FormFlattening = true;
After flattening my 2 TextField are rotated incorrectly
Image 1 of the original PDF:
Image 2 with error:
The PDF:
http://www.pdf-archive.com/2015/08/20/wyslac/
There is an issue in iText(Sharp) when flattening form fields with existing appearances rotated by means of their Matrix attribute if pdfStamper.AcroFields.GenerateAppearances is true.
The original
after flattening with GenerateAppearances == true looks like this:
Workaround
As the document already has appearance streams, you can switch off GenerateAppearances:
stamper.AcroFields.GenerateAppearances = false;
stamper.AnnotationFlattening = true;
stamper.FormFlattening = true;
The result you get now:
The issue
If GenerateAppearances == true, then iTextSharp (when flattening forms) first looks whether a field already has an appearance. If the field has one, iTextSharp only attempts to neatly fit the existing appearance into the rectangle of the form field. Unfortunately it (a) ignores the existing form field Matrix entry and (b) replaces it with a new matrix doing the fitting. If the appearance was rotated by means of its Matrix, that rotation is lost and instead the value is stretched to fit into the falsely oriented rectangle.
if (acroFields.GenerateAppearances) {
if (appDic == null || as_n == null) {
[...]
} else if (as_n.IsStream()) {
PdfStream stream = (PdfStream) as_n;
PdfArray bbox = stream.GetAsArray(PdfName.BBOX);
PdfArray rect = merged.GetAsArray(PdfName.RECT);
if (bbox != null && rect != null) {
float rectWidth = rect.GetAsNumber(2).FloatValue - rect.GetAsNumber(0).FloatValue;
float bboxWidth = bbox.GetAsNumber(2).FloatValue - bbox.GetAsNumber(0).FloatValue;
float rectHeight = rect.GetAsNumber(3).FloatValue - rect.GetAsNumber(1).FloatValue;
float bboxHeight = bbox.GetAsNumber(3).FloatValue - bbox.GetAsNumber(1).FloatValue;
float widthCoef = Math.Abs(bboxWidth != 0 ? rectWidth / bboxWidth : float.MaxValue);
float heightCoef = Math.Abs(bboxHeight != 0 ? rectHeight / bboxHeight : float.MaxValue);
if (widthCoef != 1 || heightCoef != 1)
{
NumberArray array = new NumberArray(widthCoef, 0, 0, heightCoef, 0, 0);
stream.Put(PdfName.MATRIX, array);
MarkUsed(stream);
}
}
}
}
(PdfStamperImp method FlatFields)
The background
The reason why iTextSharp ignores the appearance Matrix is that appearance generation in the course of form filling is not supposed to use such matrix values:
For non-rich text fields, the appearance stream—which, like all appearance streams, is a form XObject—has the contents of its form dictionary initialized as follows:
The resource dictionary (Resources) shall be created using resources from the interactive form dictionary’s DR entry (see Table 218).
The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect entry in the widget annotation dictionary).
All other entries in the appearance stream’s form dictionary are set to their default values (see 8.10, “Form XObjects”).
(section 12.7.3.3 "Variable Text" of ISO 32000-1)
This means for the Matrix:
Matrix array (Optional) An array of six numbers specifying the form matrix, which maps form space into user space (see 8.3.4, "Transformation Matrices"). Default value: the identity matrix [1 0 0 1 0 0].
(Table 95 – Additional Entries Specific to a Type 1 Form Dictionary - in section 8.10.2 "Form Dictionaries", ibidem)
Thus, form field appearance streams created during fill-in according to the specification, can be assumed to have a an identity Matrix value, and no rotation.
So the issue in iTextSharp actually merely reflects the assumption that form field appearances are generated due to form fill-in.
I would like to find out information about the layout of text in a PdfPCell. I'm aware of BaseFont.getWidthPointKerned(), but I'm looking for more detailed information like:
How many lines would a string need if rendered in a cell of a given width (say, 30pt)? What would the height in points of the PdfPCell be?
Give me the prefix or suffix of a string that fits in a cell of a given width and height. That is, if I have to render the text "Today is a good day to die" in a specific font in a PdfPCell of width 12pt and height 20pt, what portion of the string would fit in the available space?
Where does iText break a given string when asked to render it in a cell of a given width?
This is with regard to iText 2.1.6. Thanks.
iText uses the ColumnText class to render content to a cell. This is explained in my book on page 98-99. This means that, just like with ColumnText, you need to make the distinction between text mode and composite mode.
In any case, ColumnText measures the width of the characters and tests if they fit the available width. If not, the text is split. You can change the split behavior in different ways: by introducing hyphenation or by defining a custom split character.
I've written a small proof of concept to show how you could implement custom "truncation" behavior. See the TruncateTextInCell example.
Instead of adding the content to the cell, I have an empty cell for which I define a cell event. I pass the long text "D2 is a cell with more content than we can fit into the cell." to this event.
In the event, I use a fancy algorithm: I want the text to be truncated in the middle and insert "..." at the place where I truncated the text.
BaseFont bf = BaseFont.createFont();
Font font = new Font(bf, 12);
float availableWidth = position.getWidth();
int contentLength = content.length();
int leftChar = 0;
int rightChar = contentLength - 1;
availableWidth -= bf.getWidthPoint("...", 12);
while (leftChar < contentLength && rightChar != leftChar) {
availableWidth -= bf.getWidthPoint(content.charAt(leftChar), 12);
if (availableWidth > 0)
leftChar++;
else
break;
availableWidth -= bf.getWidthPoint(content.charAt(rightChar), 12);
if (availableWidth > 0)
rightChar--;
else
break;
}
String newContent = content.substring(0, leftChar) + "..." + content.substring(rightChar);
PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
ColumnText ct = new ColumnText(canvas);
ct.setSimpleColumn(position);
ct.addElement(new Paragraph(newContent, font));
ct.go();
As you can see, we get the available width from the position parameter and we check how many characters match, alternating between a character at the start and a character at the end of the content.
The result is shown in the resulting PDF: the content is truncated like this: "D2 is a c... the cell."
Your question about "how many lines" can be solved in a similar way. The ColumnText class has a getLinesWritten() method that gives you that information. You can find more info about positioning a ColumnText object in my answer to your other question: Can I tell iText how to clip text to fit in a cell
We are building a catalog app that has 2 rows of sorted images with varying widths but same height. We draw the artwork on scrollview in sorted order (from A to Z) As per attached image.
We search using a alphabetically ordered bar on top that has letters (A to Z) If i touch on letter J the i want the artwork which starts from j comes first. The code we are using is not working well. E.g. clicking on J takes us to A. Will greatly appreciate your help or advice.
Code is as follows:
NSString *newStr = [currentArtworkTitle substringWithRange:NSMakeRange(0,1)];
if([newStr isEqualToString:self.searchString])
if (scrollViewTopRowWidth > scrollViewBottomRowWidth) {
xCordForSortedView = scrollViewTopRowWidth - c - imgForButton.size.width;//self.touchLengthCount;//50 ;// -10//c scrollViewBottomRowWidth
}
else {
xCordForSortedView = scrollViewBottomRowWidth - c - imgForButton.size.width;// self.touchLengthCount;//40;//scrollViewTopRowWidth
}
// For shifting the screen
if(scrollViewTopRowWidth > scrollViewBottomRowWidth){
int tmpMargin = scrollViewTopRowWidth - xCordForSortedView;
if(tmpMargin < 1024)
scrollView.contentSize = CGSizeMake(scrollViewTopRowWidth+1024,scrollView.bounds.size.height);
}
else{
int tmpMargin = scrollViewBottomRowWidth - xCordForSortedView;
if(tmpMargin < 1024)
scrollView.contentSize = CGSizeMake(scrollViewBottomRowWidth+1024,scrollView.bounds.size.height);
}
[scrollView scrollRectToVisible:CGRectMake(xCordForSortedView, 0,scrollView.frame.size.width, scrollView.frame.size.height) animated:YES];
I won't edit your code but I can give you a hint.
Look, when you populate the scrollwiew, by adding an imageview, add also an entry into a NSMutableDictionary (instance variable), so the key will be the A-Z letter, and the value will be the x position of the image. When you finish populating the scrollview, you will have also the dictionary containing the position of all your images (and you need only the x) and the corresponding letter. Now you tap "J" and hit "Search" - you parse your dictionary to fing the object with the key "J" and read it's value. Use this (x) value to set your srollview's contentOffset. Tada!
I have a pie chart and I need to change the size of the symbols in the legend, but there's only setSymbolWidth. How do I change the height of the symbol?
I'm using Moxie Group's GWT highchart, but if there's a way in solving this with the javascript highcharts I'm probably able to do it in the GWT version.
I tried this solution http://jsfiddle.net/MEr2n/ but the series property is returning null (don't know why) even after I add a series to the chart. I'm also not sure this would work because it seems this solution gets the SVG element of the legend from the serie and set its property directly, in my case there is one serie and a symbol for each point in the serie.
I solved it. Unfortunately I needed to create a very ugly workaround for this. At least it worked.
My solution was:
NodeList<Element> gElements = chart.getElement().getElementsByTagName('g');
for (int i = 0; i < gElements.getLength(); i++) {
Element gel = gElements.getItem(i);
if (gel.getAttribute("class").equals("highcharts-legend")) {
NodeList<Element> elements = gel.getElementsByTagName("rect");
for (int j = 0; j < elements.getLength(); j++) {
elements.getItem(j).setAttribute("height", "8");
}
break;
}
}
I guess I could have used gwt-jquery to get the g element with the highcharts-legend class, but I don't want to add another API just for this.