How to make a LWUIT List to render its items accordingly to each item contents? - java-me

I have a LWUIT List filled with items that represents Flight objects, each Flight item displays its flight number, each of it legs departure and arrival times and the price for a ticket.
Some flights have two legs (a leg meaning a segment of a flight involving a stopover, change of aircraft, or change of airline) so these flight items needs to be rendered with each leg departure time and arrival time along with the code for the origin and destination on each leg.
At first the items with only one leg are rendered normally, but when I scroll the list and the items with more than one leg are beginning to be rendered, the items are rendered wrongly with the information cut and what is worse is that all of the items on the list are affected by this, even the ones with only one leg.
In this screenshot you can see how the list items look before reaching the items with more than one leg:
Then when I scroll the List and reach the items with more than one leg, all of the items are rendered with their leg times information cut and in place the time info of the first item with more than one leg pasted on top of their information:
Below I provide my List Renderer class:
package com.yallaya.screens.elements;
import com.dotrez.model.Flight;
import com.dotrez.model.Segment;
import com.sun.lwuit.Component;
import com.sun.lwuit.Container;
import com.sun.lwuit.Font;
import com.sun.lwuit.Label;
import com.sun.lwuit.List;
import com.sun.lwuit.layouts.BoxLayout;
import com.sun.lwuit.list.ListCellRenderer;
import com.yallaya.Main;
/*
* Renderer for a List of Flights to display
*/
public class FlightItem extends Container implements ListCellRenderer {
/*
* Components for this List Item
*/
private Label flightNumberLbl = new Label("");
private Label origin1Lbl = new Label("");
private Label destination1Lbl = new Label("");
private Label origin2Lbl = new Label("");
private Label destination2Lbl = new Label("");
private Label priceLbl = new Label("");
/*
* Constructor for this List Item
*/
public FlightItem() {
this.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
this.getStyle().setBgColor(0xf0f0f0);
this.getStyle().setBgTransparency(255);
this.getStyle().setMargin(0, 0, 0, 0);
this.getStyle().setPadding(5, 5, 0, 0);
flightNumberLbl.getStyle().setMargin(14, 0, 0, 0);
origin1Lbl.getStyle().setPadding(0, 0, 24, 0);
origin1Lbl.getStyle().setMargin(0, 0, 0, 0);
destination1Lbl.getStyle().setPadding(0, 0, 24, 0);
destination1Lbl.getStyle().setMargin(0, 0, 0, 0);
origin2Lbl.getStyle().setPadding(0, 0, 24, 0);
origin2Lbl.getStyle().setMargin(0, 0, 0, 0);
destination2Lbl.getStyle().setPadding(0, 0, 24, 0);
destination2Lbl.getStyle().setMargin(0, 0, 0, 0);
priceLbl.getStyle().setPadding(0, 0, 24, 0);
priceLbl.getStyle().setMargin(14, 0, 0, 0);
priceLbl.getStyle().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
this.addComponent(flightNumberLbl);
this.addComponent(origin1Lbl);
this.addComponent(destination1Lbl);
this.addComponent(origin2Lbl);
this.addComponent(destination2Lbl);
this.addComponent(priceLbl);
}
public void updateColorItem(boolean isSelected){
if(isSelected){
this.getStyle().setBgColor(0x9a3d96);
flightNumberLbl.getStyle().setFgColor(0xffffff);
origin1Lbl.getStyle().setFgColor(0xffffff);
destination1Lbl.getStyle().setFgColor(0xffffff);
origin2Lbl.getStyle().setFgColor(0xffffff);
destination2Lbl.getStyle().setFgColor(0xffffff);
priceLbl.getStyle().setFgColor(0xffffff);
}
else{
this.getStyle().setBgColor(0xffffff);
flightNumberLbl.getStyle().setFgColor(0x9a3d96);
origin1Lbl.getStyle().setFgColor(0x555555);
destination1Lbl.getStyle().setFgColor(0x555555);
origin2Lbl.getStyle().setFgColor(0x555555);
destination2Lbl.getStyle().setFgColor(0x555555);
priceLbl.getStyle().setFgColor(0x555555);
}
}
/*
* Functions called to render this List Item
*/
public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
Flight tmp = (Flight) value;
int displayIndex = index + 1;
flightNumberLbl.setText(displayIndex + ". " + Main.localize("VUELO") + " #" + tmp.getFlightNumber());
Segment tmpSeg = (Segment) tmp.getSegments().elementAt(0);
String originStr = Main.localize("SALIDA") + " " + "(" + tmpSeg.getOrigin().getCode() + ")" + ": " + tmpSeg.getDepartureTimeString();
String destinationStr = Main.localize("LLEGADA") + "(" + tmpSeg.getDestination().getCode() + ")" + ": " + tmpSeg.getArrivalTimeString() + "";
origin1Lbl.setText(originStr);
destination1Lbl.setText(destinationStr);
if(tmp.getSegments().size() > 1){
tmpSeg = (Segment) tmp.getSegments().elementAt(1);
originStr = Main.localize("SALIDA") + " " + "(" + tmpSeg.getOrigin().getCode() + ")" + ": " + tmpSeg.getDepartureTimeString();
destinationStr = Main.localize("LLEGADA") + "(" + tmpSeg.getDestination().getCode() + ")" + ": " + tmpSeg.getArrivalTimeString() + "";
origin2Lbl.setText(originStr);
destination2Lbl.setText(destinationStr);
}
/************************************************************************/
/******************* UPDATE PIECE OF CODE STARTS HERE *******************/
/************************************************************************/
else{
origin2Lbl.setText("");
destination2Lbl.setText("");
}
/************************************************************************/
/******************* UPDATE PIECE OF CODE ENDS HERE *******************/
/************************************************************************/
priceLbl.setText("$" + tmp.getAdultFare() + " " + tmp.getCurrency().getCode());
updateColorItem(isSelected);
return this;
}
/*
* Function called to get this component when it get focus
*/
public Component getListFocusComponent(List list) {
return this;
}
}
In other platforms this problem I believe is called "ghosting" but I haven't found a way to avoid it in LWUIT for Nokia Asha.
I know since the same renderer is used to render all of the items then this could be the cause of the problem, in which case I need a way to render one item differently if required.
How can I avoid for every item in my list to be altered when one of the items must display a different length of information?
EDIT
I updated my code, now if the current Flight object does not have more than one leg then I set the labels for the second leg with empty strings, this solves the problem on the items with only one leg.
So with that I change the topic of my question to the issue that remains on the Flight items with more than one leg, the items are not resized correctly and haven't found a way to adjust each to their contents, all of them are painted the same size.
How to make sure the items height adjust correctly?
EDIT 2
I've tried to alter the height of the renderer inside the if clause where I check how many legs (referred as segments in the model) by using the this.setHeight(800);:
if(tmp.getSegments().size() > 1){
.....
flightHolder.setHeight(800);
this.setHeight(800);
}
else{
.....
flightHolder.setHeight(200);
this.setHeight(200);
}
but couldn't get a different height size at all with that method.
Then I tried to use this.preferredH(800); and finally got a change in size:
if(tmp.getSegments().size() > 1){
......
flightHolder.setPreferredH(800);
this.setPreferredH(800);
}
else{
...........
flightHolder.setPreferredH(200);
this.setPreferredH(200);
}
but all of the items are rendered with 800, which I guess is due to the last flight having more than one leg but I really don't know, I was hoping setting a bigger height for flights with more than one leg and then resetting to a smaller height for those with only one would work but it seems the height is forced the same on every item, can someone confirm this to me?

Okay. Try this:
First you need to declare a global variable to hold the default row height. Then in the constructor do .setPreferredHeight(to that default height global variable).
Now in your:
if(tmp.getSegments().size() > 1){
Set the global variable row height to be *(multiplied) by the number of segments and you should have the correct row height.
You can do similar with the margins/padding, using the number of segments to position the elements accordingly.
I hope this helped and let me know how you get on.
Fenix

Related

UIScrollView is stopping too soon

I'm using a scrollview to make a image gallery for my app and I have it mostly working. it'll allow me to scroll through the images one by one but the very last image always get cut off and I'm not sure why.
this is the bulk of the operation:
var idx = 0;
foreach (var mediaItem in _mediaItems)
{
var xPosition = UIScreen.MainScreen.Bounds.Width * idx;
var imageView = new UIImageView();
imageView.SetImage(new NSUrl(mediaItem), UIImage.FromBundle("image_placeholder"));
imageView.Frame = new CGRect(xPosition, 0, svGallery.Frame.Width + 50, svGallery.Frame.Height);
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
svGallery.ContentSize = new CGSize
{
Width = svGallery.Frame.Width * (idx + 1)
};
svGallery.AddSubview(imageView);
idx++;
}
minus that flaw, this works perfectly and as I expect it to.
From shared code , the Width of ContenSize is:
Width = svGallery.Frame.Width * (idx + 1)
However, each Width(svGallery.Frame.Width + 50) of ImageView is greater than vGallery.Frame.Width:
imageView.Frame = new CGRect(xPosition, 0, svGallery.Frame.Width + 50, svGallery.Frame.Height);
Therefore, the actually Width of ContenSize can not contains all the ImageView's Content. And if the number of ImageView is larger, the last picture will be cut off more.
You can modif the Width of ContentSize as follow to check whether it works:
svGallery.ContentSize = new CGSize
{
Width = (svGallery.Frame.Width + 50) * (idx + 1)
};

MFC ComboBox keeps the list void after deleting its items

I have a MFC ComboBox with some items as shown below:
When I delete the items with the following code:
void CComboBoxTestDlg::OnBnClickedButtonClear()
{
CComboBox *pCmb = (CComboBox *)GetDlgItem(IDC_COMBO);
pCmb->ResetContent();
}
It deletes the strings inside the ComboBox but it keeps the list void with the same height as if it had items inside as shown below:
I tried also this code:
for (int i = pCmb->GetCount() - 1; i >= 0; i--)
pCmb->DeleteString(i);
and also deletes the items inside, but it keeps the undesired list void.
Is there any way to delete the contents of the ComboBox without keeping the remaining void list?
Try this:
When the number of items in the drop down list becomes zero, call this:
CRect rect;
pCmb->GetClientRect(&rect);
pCmb->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height() + 1, SWP_NOMOVE);
Now the drop down box has a minimal height.
When the number of items in the drop down list non zero (that is as soon as you add an item), call this:
CRect rect;
pCmb->GetClientRect(&rect);
pCmb->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height() * N, SWP_NOMOVE);
where N is the desired maximum height in lines of the dropdown box of the combobox.

Epplus SetPosition picture issue

I am using Epplus library to generate Excel 2010 and up compatible files in Asp.Net C#.
I am using version 3.1.2 which is the latest at this moment.
I am setting the row height first, before adding any pictures like this:
ExcelPackage pck = new ExcelPackage();
var ws = pck.Workbook.Worksheets.Add("sheet 1");
while (i < dt.Rows.Count + offset)
{
ws.Row(i).Height = 84;
i++;
}
dt is my DataTable with DataRows.
After setting the height, I am looping again through the rows to add the pictures
while (i < dt.Rows.Count + offset)
{
var prodImg = ws.Drawings.AddPicture(dr["code"].ToString(), new FileInfo(path));
prodImg.SetPosition(i - 1, 0, 14, 0);
prodImg.SetSize(75);
}
This works, but this does not:
var prodImg = ws.Drawings.AddPicture(dr["code"].ToString(), new FileInfo(path));
int w = prodImg.Image.Width;
int h = prodImg.Image.Height;
if (h > 140) // because height of 84 is 140 pixels in excel
{
double scale = h / 140.0;
w = (int)Math.Floor(w / scale);
h = 140;
}
int xOff = (150 - w) / 2;
int yOff = (140 - h) / 2;
prodImg.SetPosition(i - 1, xOff, 11, yOff);
prodImg.SetSize(w, h);
This results in off center pictures and unresized images. And this code then which is in the same loop:
var prodImgDm = ws.Drawings.AddPicture("bcdm" + dr["code"].ToString(), new FileInfo(pathDm));
prodImgDm.SetPosition(i - 1, 25, 15, 40);
prodImgDm.SetSize(100);
This does work sometimes. the pictures prodImgDm are datamatrix images with a static width and height and do not need to be resized because they are always small/tiny. So also without the SetSize in some rows, it works and in some other rows, it does not work. Really strange because the code is the same. It might be something in the library and/or Excel. Perhaps I am using it wrong? Any epplus picture expert?
Thanks in advance!!
edit sometimes a picture is worth a thousand words, so here is the screenshot. As you can see the product images are not horizontal and vertical aligned in the cell. And the datamatrix on the far right is sometimes scaled about 120% even when I set SetSize(100) so it is really strange to me. So the last datamatrix has the correct size... I already found this SO thread but that does not help me out, I think.
edit 2013/04/09 Essenpillai gave me a hint to set
pck.DoAdjustDrawings = false;
but that gave me even stranger images:
the datamatrix is still changing on row basis. on row is ok, the other is not. and the ean13 code is too wide.
public static void CreatePicture(ExcelWorksheet worksheet, string name, Image image, int firstColumn, int lastColumn, int firstRow, int lastRow, int defaultOffsetPixels)
{
int columnWidth = GetWidthInPixels(worksheet.Cells[firstRow, firstColumn]);
int rowHeight = GetHeightInPixels(worksheet.Cells[firstRow, firstColumn]);
int totalColumnWidth = columnWidth * (lastColumn - firstColumn + 1);
int totalRowHeight = rowHeight * (lastRow - firstRow + 1);
double cellAspectRatio = Convert.ToDouble(totalColumnWidth) / Convert.ToDouble(totalRowHeight);
int imageWidth = image.Width;
int imageHeight = image.Height;
double imageAspectRatio = Convert.ToDouble(imageWidth) / Convert.ToDouble(imageHeight);
int pixelWidth;
int pixelHeight;
if (imageAspectRatio > cellAspectRatio)
{
pixelWidth = totalColumnWidth - defaultOffsetPixels * 2;
pixelHeight = pixelWidth * imageHeight / imageWidth;
}
else
{
pixelHeight = totalRowHeight - defaultOffsetPixels * 2;
pixelWidth = pixelHeight * imageWidth / imageHeight;
}
int rowOffsetPixels = (totalRowHeight - pixelHeight) / 2;
int columnOffsetPixels = (totalColumnWidth - pixelWidth) / 2;
int rowOffsetCount = 0;
int columnOffsetCount = 0;
if (rowOffsetPixels > rowHeight)
{
rowOffsetCount = (int)Math.Floor(Convert.ToDouble(rowOffsetPixels) / Convert.ToDouble(rowHeight));
rowOffsetPixels -= rowHeight * rowOffsetCount;
}
if (columnOffsetPixels > columnWidth)
{
columnOffsetCount = (int)Math.Floor(Convert.ToDouble(columnOffsetPixels) / Convert.ToDouble(columnWidth));
columnOffsetPixels -= columnWidth * columnOffsetCount;
}
int row = firstRow + rowOffsetCount - 1;
int column = firstColumn + columnOffsetCount - 1;
ExcelPicture pic = worksheet.Drawings.AddPicture(name, image);
pic.SetPosition(row, rowOffsetPixels, column, columnOffsetPixels);
pic.SetSize(pixelWidth, pixelHeight);
}
public static int GetHeightInPixels(ExcelRange cell)
{
using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
{
float dpiY = graphics.DpiY;
return (int)(cell.Worksheet.Row(cell.Start.Row).Height * (1 / 72.0) * dpiY);
}
}
public static float MeasureString(string s, Font font)
{
using (var g = Graphics.FromHwnd(IntPtr.Zero))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
return g.MeasureString(s, font, int.MaxValue, StringFormat.GenericTypographic).Width;
}
}
public static int GetWidthInPixels(ExcelRange cell)
{
double columnWidth = cell.Worksheet.Column(cell.Start.Column).Width;
Font font = new Font(cell.Style.Font.Name, cell.Style.Font.Size, FontStyle.Regular);
double pxBaseline = Math.Round(MeasureString("1234567890", font) / 10);
return (int)(columnWidth * pxBaseline);
}
enter image description here
I have the same problem with Epplus library.
After I find no solution how to solve this in my code, I checked source code of this library.
Epplus create excel picture always as twoCellAnchor drawing. In xlsx files you can find drawingXYZ.xml with this code:
<xdr:twoCellAnchor editAs="oneCell">
<xdr:from> ... </xdr:from>
<xdr:to> ... </xdr:to>
<xdr:pic>
...
</xdr:twoCellAnchor>
So, picture is always connected to two cells, and this is not variable part of Epplus library. You can find this part of code in ExcelDrawing.cs file.
XmlElement drawNode = _drawingsXml.CreateElement(
"xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings);
colNode.AppendChild(drawNode);
You can easy create your own copy of this dll. The good news is that you need to modify only two files to fix this problem. So..
Download your copy of source codes for Epplus library from this site and open in Visual Studio.
We need to generate code of drawing as oneCellAnchor, so we must remove <xdr:to> element for pictures and create element <xdr:ext /> with picture dimensions as parameters.
New xml structure will looks like:
<xdr:oneCellAnchor editAs="oneCell">
<xdr:from> ... </xdr:from>
<xdr:ext cx="1234567" cy="7654321" />
<xdr:pic>
...
</xdr:oneCellAnchor>
Ok, so, how to do this?
Changes in Epplus code
ExcelDrawings.cs (link to file here)
At first we modify method CreateDrawingXml() inside ExcelDrawings.cs. Order to preserve the original functionality we add an optional parameter (if create oneCellAnchor) with default value. And in method, based this parameter, we create one or tow cell anchor and create or not <xdr:to> element.
Important part of this method code:
private XmlElement CreateDrawingXml(bool twoCell = true) {
if (DrawingXml.OuterXml == "")
{ ... } // not changed
XmlNode colNode= _drawingsXml.SelectSingleNode("//xdr:wsDr", NameSpaceManager);
//First change in method code
XmlElement drawNode;
if (twoCell)
drawNode = _drawingsXml.CreateElement(
"xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings);
else
drawNode = _drawingsXml.CreateElement(
"xdr", "oneCellAnchor", ExcelPackage.schemaSheetDrawings);
colNode.AppendChild(drawNode);
//Add from position Element; // Not changed
XmlElement fromNode = _drawingsXml.CreateElement(
"xdr", "from", ExcelPackage.schemaSheetDrawings);
drawNode.AppendChild(fromNode);
fromNode.InnerXml = "<xdr:col>0</xdr:col><xdr:colOff>0</xdr:colOff>"
+ "<xdr:row>0</xdr:row><xdr:rowOff>0</xdr:rowOff>";
//Add to position Element;
//Second change in method
if (twoCell)
{
XmlElement toNode = _drawingsXml.CreateElement(
"xdr", "to", ExcelPackage.schemaSheetDrawings);
drawNode.AppendChild(toNode);
toNode.InnerXml = "<xdr:col>10</xdr:col><xdr:colOff>0</xdr:colOff>"
+ "<xdr:row>10</xdr:row><xdr:rowOff>0</xdr:rowOff>";
}
return drawNode;
}
Then we modify two methods for AddPicture inside the same file:
public ExcelPicture AddPicture(string Name, Image image, Uri Hyperlink)
{
if (image != null) {
if (_drawingNames.ContainsKey(Name.ToLower())) {
throw new Exception("Name already exists in the drawings collection");
}
XmlElement drawNode = CreateDrawingXml(false);
// Change: we need create element with dimensions
// like: <xdr:ext cx="3857625" cy="1047750" />
XmlElement xdrext = _drawingsXml.CreateElement(
"xdr", "ext", ExcelPackage.schemaSheetDrawings);
xdrext.SetAttribute("cx",
(image.Width * ExcelDrawing.EMU_PER_PIXEL).ToString());
xdrext.SetAttribute("cy",
(image.Height * ExcelDrawing.EMU_PER_PIXEL).ToString());
drawNode.AppendChild(xdrext);
// End of change, next part of method is the same:
drawNode.SetAttribute("editAs", "oneCell");
...
}
}
And this method with FileInfo as input parameter:
public ExcelPicture AddPicture(string Name, FileInfo ImageFile, Uri Hyperlink)
{
if (ImageFile != null) {
if (_drawingNames.ContainsKey(Name.ToLower())) {
throw new Exception("Name already exists in the drawings collection");
}
XmlElement drawNode = CreateDrawingXml(false);
// Change: First create ExcelPicture object and calculate EMU dimensions
ExcelPicture pic = new ExcelPicture(this, drawNode, ImageFile, Hyperlink);
XmlElement xdrext = _drawingsXml.CreateElement(
"xdr", "ext", ExcelPackage.schemaSheetDrawings);
xdrext.SetAttribute("cx",
(pic.Image.Width * ExcelDrawing.EMU_PER_PIXEL).ToString());
xdrext.SetAttribute("cy",
(pic.Image.Height * ExcelDrawing.EMU_PER_PIXEL).ToString());
drawNode.AppendChild(xdrext);
// End of change, next part of method is the same (without create pic object)
drawNode.SetAttribute("editAs", "oneCell");
...
}
}
So, this are all important code. Now we must change code for searching nodes and preserve order in elements.
In private void AddDrawings() we change xpath from:
XmlNodeList list = _drawingsXml.SelectNodes(
"//xdr:twoCellAnchor", NameSpaceManager);
To this:
XmlNodeList list = _drawingsXml.SelectNodes(
"//(xdr:twoCellAnchor or xdr:oneCellAnchor)", NameSpaceManager);
It is all in this file, now we change
ExcelPicture.cs (link to file here)
Original code find node for append next code in constructor like this:
node.SelectSingleNode("xdr:to",NameSpaceManager);
Because we do not create <xdr:to> element always, we change this code:
internal ExcelPicture(ExcelDrawings drawings, XmlNode node
, Image image, Uri hyperlink)
: base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/#name")
{
XmlElement picNode = node.OwnerDocument.CreateElement(
"xdr", "pic", ExcelPackage.schemaSheetDrawings);
// Edited: find xdr:to, or xdr:ext if xdr:to not exists
XmlNode befor = node.SelectSingleNode("xdr:to",NameSpaceManager);
if (befor != null && befor.Name == "xdr:to")
node.InsertAfter(picNode, befor);
else {
befor = node.SelectSingleNode("xdr:ext", NameSpaceManager);
node.InsertAfter(picNode, befor);
}
// End of change, next part of constructor is unchanged
_hyperlink = hyperlink;
...
}
And the same for second constructor with FileInfo as input parameter:
internal ExcelPicture(ExcelDrawings drawings, XmlNode node
, FileInfo imageFile, Uri hyperlink)
: base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/#name")
{
XmlElement picNode = node.OwnerDocument.CreateElement(
"xdr", "pic", ExcelPackage.schemaSheetDrawings);
// Edited: find xdr:to, or xdr:ext if xdr:to not exists
XmlNode befor = node.SelectSingleNode("xdr:to", NameSpaceManager);
if (befor != null && befor.Name == "xdr:to")
node.InsertAfter(picNode, befor);
else {
befor = node.SelectSingleNode("xdr:ext", NameSpaceManager);
node.InsertAfter(picNode, befor);
}
// End of change, next part of constructor is unchanged
_hyperlink = hyperlink;
...
Now, pictures are created as oneCellAnchor. If you want, you can create multiple AddPicture methods for booth variants. Last step is build this project and create your own custom EPPlus.dll. Then close your project which use this dll and copy new files EPPlus.dll, EPPlus.pdb, EPPlus.XML inside your project (backup and replace your original dll files) at the same place (so you don't need do any change in your project references or settings).
Then open and rebuild your project and try if this solve your problem.
Maybe I am too late, but here is mine answer..
you can read it on codeplex issue as well
(https://epplus.codeplex.com/workitem/14846)
I got this problem as well.
And after some research I figured out where the bug is.
It's in the ExcelRow class on the 149 line of code (ExcelRow.cs file).
There is a mistake, when row's Height got changed it recalcs all pictures heights but uses pictures widths inplace of heights, so it's easy to fix.
Just change the line
var pos = _worksheet.Drawings.GetDrawingWidths();
to
var pos = _worksheet.Drawings.GetDrawingHeight();
See the code changes on image
P.S. Actual for version 4.0.4

Unity3d Box Collider Vertex

How do I get the vertexes of a box collider in world space in Unity3d? (with correct rotation and scale). Just doing local-world on the object does not work.
obj.transform.localToWorldMatrix.MultiplyPoint3x4(extents); and doing similar things for the other corners is what I tried.
Since you can easily get the BoxCollider's centre and extents you can get the local vertex position easily by adding or subtracting the extent from the centre, then transforming it into global world space with a method like Vector3.TransformPoint()
The following script prints the global position of each vertex of a BoxCollider attached to the same GameObject as the script, every Update() call.
using System.Collections;
public class DebugPrintColliderVertices : MonoBehaviour
{
const uint NUM_VERTICES = 8;
private BoxCollider boxCollider;
private Transform[] vertices;
void Awake()
{
boxCollider = (BoxCollider)this.gameObject.GetComponent(typeof(BoxCollider));
if (boxCollider == null)
{
Debug.Log ("Collider not found on " + this.gameObject.name + ". Ending script.");
this.enabled = false;
}
vertices = new Transform[NUM_VERTICES];
}
void Update()
{
Vector3 colliderCentre = boxCollider.center;
Vector3 colliderExtents = boxCollider.extents;
for (int i = 0; i != NUM_VERTICES ; ++i)
{
Vector3 extents = colliderExtents;
extents.Scale (new Vector3((i & 1) == 0 ? 1 : -1, (i & 2) == 0 ? 1 : -1, (i & 4) == 0 ? 1 : -1));
Vector3 vertexPosLocal = colliderCentre + extents;
Vector3 vertexPosGlobal = boxCollider.transform.TransformPoint(vertexPosLocal);
// display vector3 to six decimal places
Debug.Log ("Vertex " + i + " # " + vertexPosGlobal.ToString("F6"));
}
}
}
Note that the BoxCollider's size is multiplied by the transform.scale of the GameObject it's attached to. I haven't included that calculation in said script, but finding the overall rotation/scale should be fairly trivial from this point.

Unity3D ScrollView scroll range

I'm trying to create a scrollView, but I don't know how to determine the maximum range of the scroll (or even better, the maximum scroll position).
This is what I have tried to do without any positive results:
void Update()
{
//get the amount of space that my text is taking
textSize = gs.CalcHeight(new GUIContent(text), (screenWidth/2));
if(Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(0).tapCount==1)
{
var touch = Input.touches[0];
//check if touch is within the scrollView area
if(touch.position.x >= (screenWidth/2) && touch.position.x <= (screenWidth) && touch.position.y >= 0 && touch.position.y <= (screenHeight))
{
if(touch.phase == TouchPhase.Moved)
{
scrollPosition[1] += touch.deltaPosition.y;
if(scrollPosition[1] < 0)
{
scrollPosition[1] = 0;
}
//I subtracted this cause i read that the scrollbars take 16px
if(scrollPosition[1] > (textSize-scrollViewRect.yMax-16)) //scrollViewRect is a Rect with the size of my scrollView
{
scrollPosition[1] = textSize-scrollViewRect.yMax-16;
}
}
}
}
}
void OnGUI()
{
screenWidth = camera.pixelWidth;
screenHeight = camera.pixelHeight;
GUILayout.BeginArea(new Rect(screenWidth/2, 0, screenWidth/2, screenHeight));
GUILayout.BeginScrollView(scrollPosition/*, GUILayout.Width (screenWidth/2), GUILayout.Height (screenHeight/2)*/, "box");
GUILayout.Label (new GUIContent(text), gs);
// End the scrollview
GUILayout.EndScrollView ();
scrollViewRect = GUILayoutUtility.GetLastRect();
GUILayout.EndArea();
}
This was done assuming that the scrollView is on the right half of the screen.
Can you guys help me out on this?
Thanks in advance.
As shown in the API documentation for GUI.BeginScrollView, you can assign a Vector2 to the declaration of BeginScrollView to track and update where the box has been scrolled to.
I'll give an example:
using UnityEngine;
using System.Collections;
public class ScrollSize : MonoBehaviour {
private int screenBoxX = Screen.width;
private int screenBoxY = Screen.height;
private int scrollBoxX = Screen.width * 2;
private int scrollBoxY = Screen.height * 3;
public Vector2 scrollPosition = Vector2.zero;
void Awake()
{
Debug.Log ("box size is " + scrollBoxX + " " + scrollBoxY);
}
void OnGUI()
{
scrollPosition = GUI.BeginScrollView(new Rect(0, 0, screenBoxX, screenBoxY),
scrollPosition, new Rect(0, 0, scrollBoxX, scrollBoxY));
GUI.EndScrollView();
// showing 4 decimal places
Debug.Log ("Box scrolled # " + scrollPosition.ToString("F4"));
}
}
For the explanation of this example, let's assume that the screen resolution is 800 by 600.
Therefore the viewable scrollbox on the screen will be 800 wide and 600 high, with the internal area of the scrollbox being 1600 by 1800.
We create the scrollbox by assigning Gui.BeginScrollView() as the value of Vector2, scrollPosition. As the scrollbox is scrolled horizontally and vertically, the Vector2 will update with the scrolled value.
If the scrollbox is scrolled to the top-leftmost position, the value of scrollPosition will be 0,0.
If the scrollbox is scrolled to the bottom-rightmost position, the value of scrollPosition will be 816, 616, the size of the box on screen plus the thickness of the scroll bars.
I know this is 3 years later but maybe it will help others too...
I found that setting the scrollPosition to a very high number will force the scrollbar to the bottom:
scrollPosition.y = 999.9f;
Then you can read the position like this:
scrollPosition = GUILayout.BeginScrollView(scrollPosition,
GUILayout.Width(370),
GUILayout.Height(135));
And it will be set to whatever the maximum is.
Hope this helps!

Resources