private void SetupTableContentPositionRecursively(VirtualGameObject child, TableLayoutRecord tableLayoutRecord) { // overwrite parent content width of TH and TD. if (child.tag == Tag.THEAD || child.tag == Tag.TBODY || child.tag == Tag.THEAD || child.tag == Tag.TR) { var width = tableLayoutRecord.TotalWidth(); child.vRectTransform.vSizeDelta = new Vector2(width, child.vRectTransform.vSizeDelta.y); } /* * change TH, TD content's x position and width. * x position -> 0, 1st row's longest content len, 2nd row's longest content len,... * width -> 1st row's longest content len, 2nd row's longest content len,... */ if (child.tag == Tag.TH || child.tag == Tag.TD) { var offsetAndWidth = tableLayoutRecord.GetOffsetAndWidth(); child.vRectTransform.vAnchoredPosition = new Vector2(offsetAndWidth.offset, child.vRectTransform.vAnchoredPosition.y); child.vRectTransform.vSizeDelta = new Vector2(offsetAndWidth.width, child.vRectTransform.vSizeDelta.y); } foreach (var nestedChild in child.transform.GetChildlen()) { child.SetupTableContentPositionRecursively(nestedChild, tableLayoutRecord); } }
private void CollectTableContentRowCountRecursively(VirtualGameObject child, TableLayoutRecord tableLayoutRecord) { // count up table header count. if (child.tag == Tag.TH) { tableLayoutRecord.IncrementRow(); } foreach (var nestedChild in child.transform.GetChildlen()) { child.CollectTableContentRowCountRecursively(nestedChild, tableLayoutRecord); } }
private void DoLayoutTagContentRecursively(VirtualGameObject child, float offsetX, float offsetY, float viewWidth, float viewHeight, MaxPoints maxPoints) { if (child.tag == Tag.TH) { maxPoints.AddXCount(); } // もし子供ゾーンに入ったら、その時点でmaxPointの値を指定していいはず。 // で。それを抜けたら、場で保持しているパラメータを、viewWidthとして指定できる! child.LayoutTagContent(offsetX, offsetY, viewWidth, viewHeight, (a) => {}); foreach (var nestedChild in child.transform.GetChildlen()) { child.DoLayoutTagContentRecursively(nestedChild, offsetX, offsetY, viewWidth, viewHeight, maxPoints); } }
public TagPoint(Tag tag, string parentRawTag, Tag[] depth, Dictionary <KV_KEY, string> kv, string originalTagName) { this.tag = tag; this.depth = depth; this.originalTagName = originalTagName; var prefabName = string.Empty; switch (tag) { case Tag._CONTENT: { prefabName = parentRawTag; break; } // these are container. case Tag.EM: case Tag.STRONG: case Tag.PRE: case Tag.BLOCKQUOTE: case Tag.CODE: case Tag.H: case Tag.P: case Tag.A: case Tag.UL: case Tag.LI: case Tag.OL: case Tag.TABLE: case Tag.THEAD: case Tag.TBODY: case Tag.TR: case Tag.TH: case Tag.TD: { // these are container. prefabName = originalTagName.ToUpper() + "Container"; break; } default: { prefabName = originalTagName.ToUpper(); break; } } this.vGameObject = new VirtualGameObject(tag, depth, kv, prefabName); }
private void CollectTableContentRowMaxWidthsRecursively(VirtualGameObject child, TableLayoutRecord tableLayoutRecord) { var total = 0f; foreach (var nestedChild in child.transform.GetChildlen()) { child.CollectTableContentRowMaxWidthsRecursively(nestedChild, tableLayoutRecord); if (child.tag == Tag.TH || child.tag == Tag.TD) { var nestedChildContentWidth = nestedChild.vRectTransform.vSizeDelta.x; total += nestedChildContentWidth; } } if (child.tag == Tag.TH || child.tag == Tag.TD) { tableLayoutRecord.UpdateMaxWidth(total); } }
private void Materialize(VirtualGameObject parent, Tokenizer.OnMaterializeDelegate onMaterializeDel) { switch (this.tag) { case Tag.ROOT: { // do nothing. break; } case Tag.BR: { // has no child. no visual. do nothing. break; } default: { this._gameObject = MaterializeTagContent(); this._gameObject.transform.SetParent(parent._gameObject.transform, false); var rectTrans = this._gameObject.GetComponent <RectTransform>(); if (rectTrans == null) { return; } // set position. convert layout position to uGUI position system. rectTrans.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, -rectTransform.anchoredPosition.y); // Debug.LogError("materialize rectTrans.anchoredPosition:" + rectTrans.anchoredPosition); rectTrans.sizeDelta = rectTransform.sizeDelta; break; } } foreach (var child in this.transform.GetChildlen()) { child.Materialize(this, onMaterializeDel); } onMaterializeDel(this._gameObject, this.tag, this.depth, new Dictionary <KV_KEY, string>(this.keyValueStore)); }
public Tokenizer(string source) { var root = new TagPoint(Tag.ROOT, string.Empty, new Tag[0], new Dictionary <KV_KEY, string>(), string.Empty); rootObject = Tokenize(root, source.Replace("\n", string.Empty)); }
private ContentAndWidthAndHeight LayoutTextContent(float offset, string text, float contentWidth, float contentHeight, Action <List <VirtualGameObject> > insert) { // このあたりをhttpリクエストに乗っけるようなことができるとなおいいのだろうか。AssetBundleともちょっと違う何か、的な。 /* * ・Resourcesに置ける * ・AssetBundle化できる */ var prefab = LoadPrefab(prefabName); if (prefab == null) { return(new ContentAndWidthAndHeight()); } // Debug.LogError("prefabName:" + prefabName); // use prefab's text component for using it's text setting. var textComponent = prefab.GetComponent <Text>(); if (textComponent == null) { throw new Exception("failed to get Text component from prefab:" + prefabName); } // set content first. textComponent.text = text; // Debug.LogError("offset:" + offset + " text:" + text); var generator = new TextGenerator(); var setting = textComponent.GetGenerationSettings(new Vector2(contentWidth - offset, contentHeight)); generator.Populate(text, setting); var lines = new List <string>(); var nextText = text; // get copy. if (generator.lineCount == 0) { // no line layouted. set this text to next line. var nextLineVGameObject = new VirtualGameObject( this.tag, this.depth, new Dictionary <KV_KEY, string>() { { KV_KEY._CONTENT, nextText } }, this.prefabName ); insert(new List <VirtualGameObject> { nextLineVGameObject }); // return empty line. new ContentAndWidthAndHeight(string.Empty, 0, 0); } while (true) { // if rest text is included by one line, line collection is done. if (generator.lineCount == 1) { lines.Add(nextText); break; } // Debug.LogError("nextText:" + nextText + " generator.lines.Count:" + generator.lines.Count); // 複数行が出たので、continue, // 折り返しが発生したところから先のtextを取得し、その前までをコンテンツとしてセットする必要がある。 var nextTextLineInfo = generator.lines[1]; var startIndex = nextTextLineInfo.startCharIdx; lines.Add(nextText.Substring(0, startIndex)); nextText = nextText.Substring(startIndex); // ここから先の行は、今は見る必要がなくて、ターゲットを切り替えて再度実行する。 textComponent.text = nextText; // populate again. generator.Invalidate(); // ここで、幅は与えられている最大のものを使えるはず(親から伝わってくる時点で本来はすり減ったのが来てるはず) generator.Populate(textComponent.text, textComponent.GetGenerationSettings(new Vector2(contentWidth, contentHeight))); if (generator.lineCount == 0) { throw new Exception("no line detected 2. nextText:" + nextText); } } textComponent.text = lines[0]; var preferredWidth = textComponent.preferredWidth; // reset. textComponent.text = string.Empty; /* * insert new line contents after this content. */ if (1 < lines.Count) { var newContentTexts = lines.GetRange(1, lines.Count - 1); // foreach (var s in newContentTexts) { // Debug.LogError("s:" + s); // } var newVGameObjects = newContentTexts.Select( t => new VirtualGameObject( this.tag, this.depth, new Dictionary <KV_KEY, string>() { { KV_KEY._CONTENT, t } }, this.prefabName ) ).ToList(); insert(newVGameObjects); } // Debug.LogError("preferredWidth:" + preferredWidth); return(new ContentAndWidthAndHeight(lines[0], preferredWidth, generator.lines[0].height)); }
/** * layout contents. * * set position and size of content. */ private HandlePoint Layout(VirtualGameObject parent, HandlePoint handlePoint, Tokenizer.OnLayoutDelegate onLayoutDel, Action <List <VirtualGameObject> > insert) { switch (this.tag) { case Tag.ROOT: { // do nothing. break; } default: { LayoutTagContent(handlePoint.nextLeftHandle, handlePoint.nextTopHandle, handlePoint.viewWidth, handlePoint.viewHeight, insert); break; } } // parent layout is done. will be resized by child, then padding. var childlen = this.transform.GetChildlen(); if (0 < childlen.Count) { LayoutChildlen(childlen, handlePoint, onLayoutDel); /* * set parent = this content's size to wrapping all childlen. */ var rightBottomPoint = Vector2.zero; // fit most large bottom-right point. largest point of width and y. foreach (var child in childlen) { var paddedRightBottomPoint = child.PaddedRightBottomPoint(); if (rightBottomPoint.x < paddedRightBottomPoint.x) { rightBottomPoint.x = paddedRightBottomPoint.x; } if (rightBottomPoint.y < paddedRightBottomPoint.y) { rightBottomPoint.y = paddedRightBottomPoint.y; } } // fit size to wrap all child contents. vRectTransform.vSizeDelta = rightBottomPoint; // calculate table's contents. if (this.tag == Tag.TABLE) { /* * all contents size calculation inside this table is done. * count up row, * find longest content, * and adjust left point of contents. */ var tableLayoutRecord = new TableLayoutRecord(); // countup rows. foreach (var tableChild in this.transform.GetChildlen()) { CollectTableContentRowCountRecursively(tableChild, tableLayoutRecord); } // find longest content. foreach (var tableChild in this.transform.GetChildlen()) { CollectTableContentRowMaxWidthsRecursively(tableChild, tableLayoutRecord); } // resize & reset position of this table contents by calculated record. foreach (var tableChild in this.transform.GetChildlen()) { SetupTableContentPositionRecursively(tableChild, tableLayoutRecord); } } } /* * set padding if need. * default padding is 0. */ onLayoutDel(this.tag, this.depth, this.padding, this.keyValueStore); /* * adopt padding to this content. */ { // translate anchor position of content.(child follows parent.) vRectTransform.vAnchoredPosition += padding.LeftTopPoint(); handlePoint.nextLeftHandle += padding.PadWidth(); handlePoint.nextTopHandle += padding.PadHeight(); // Debug.LogWarning("実験した方が良さそう"); } // Debug.LogError("rectTransform.anchoredPosition:" + rectTransform.anchoredPosition); /* * set next left-top point by parent tag kind. */ switch (parent.tag) { default: { // 回り込みを実現する。んだけど、これはどちらかというと多数派で、デフォルトっぽい。 // next content is planned to layout to the next of this content. handlePoint.nextLeftHandle = this.vRectTransform.vAnchoredPosition.x + this.vRectTransform.vSizeDelta.x + this.padding.PadWidth(); // right edge with padding // Debug.LogError("handlePoint.nextLeftHandle:" + handlePoint.nextLeftHandle); break; } // Rootコンテンツにぶらさがっている項目は、全てCRLFがかかる。 case Tag.ROOT: { // CRLF handlePoint.nextLeftHandle = 0; handlePoint.nextTopHandle += this.vRectTransform.vSizeDelta.y + this.padding.PadHeight(); // Debug.LogError("親がRootなので、改行する。handlePoint.nextTopHandle:" + handlePoint.nextTopHandle + " of tag:" + tag + " rectTransform.anchoredPosition:" + this.rectTransform.anchoredPosition); break; } } return(handlePoint); }
public VirtualTransform(VirtualGameObject gameObject) { this.vGameObject = gameObject; }
/** * layout contents. * * set position and size of content. */ private HandlePoint Layout(VirtualGameObject parent, HandlePoint handlePoint, Tokenizer.OnLayoutDelegate onLayoutDel, Action <List <VirtualGameObject> > insert) { switch (this.tag) { case Tag.ROOT: { // do nothing. break; } default: { // Debug.LogError("before layout rectTransform.anchoredPosition:" + rectTransform.anchoredPosition + " of tag:" + tag + " handlePoint:" + handlePoint.nextTopHandle); LayoutTagContent(handlePoint.nextLeftHandle, handlePoint.nextTopHandle, handlePoint.viewWidth, handlePoint.viewHeight, insert); // Debug.LogError("after layout rectTransform.anchoredPosition:" + rectTransform.anchoredPosition + " of tag:" + tag + " handlePoint:" + handlePoint.nextTopHandle); break; } } // parent layout is done. will be resized by child, then padding. // calculate table's column count. if (this.tag == Tag.TABLE) { // ハンドラで、n x m のテーブルであることが通知できる。 // 別の話、N文字目に改行があったことが記録として残せるので、要素にidを振ることができる。 // n x mがわかったら、それぞれの幅をどうしたいかを通知できるはず。 // 指定したら、その幅を採用する。レイアウトも溢れも。ということはできそう。 // ッツー感じか。n単位でwidthを返せばいいので、nを受け取ってn x widthを返すのでよさげ。 var maxPoints = new MaxPoints(); // pre-layout table contents. foreach (var tableChild in this.transform.GetChildlen()) { DoLayoutTagContentRecursively(tableChild, handlePoint.nextLeftHandle, handlePoint.nextTopHandle, handlePoint.viewWidth, handlePoint.viewHeight, maxPoints); } } var childlen = this.transform.GetChildlen(); if (0 < childlen.Count) { LayoutChildlen(childlen, handlePoint, onLayoutDel); /* * set parent = this content's size to wrapping all childlen. */ var rightBottomPoint = Vector2.zero; // fit most large bottom-right point. largest point of width and y. foreach (var child in childlen) { var paddedRightBottomPoint = child.PaddedRightBottomPoint(); if (rightBottomPoint.x < paddedRightBottomPoint.x) { rightBottomPoint.x = paddedRightBottomPoint.x; } if (rightBottomPoint.y < paddedRightBottomPoint.y) { rightBottomPoint.y = paddedRightBottomPoint.y; } } // fit size to wrap all child contents. rectTransform.sizeDelta = rightBottomPoint; // Debug.LogError("set wrap rectTransform.sizeDelta:" + rectTransform.sizeDelta + " of tag:" + tag); // Debug.LogError("after wrap rectTransform.anchoredPosition:" + rectTransform.anchoredPosition + " of tag:" + tag + " handlePoint:" + handlePoint.nextTopHandle); // layout and padding and orientation of child tags are done. } /* * set padding if need. * default padding is 0. */ onLayoutDel(this.tag, this.depth, this.padding, this.keyValueStore); /* * adopt padding to this content. */ { // translate anchor position of content.(child follows parent.) rectTransform.anchoredPosition += padding.LeftTopPoint(); handlePoint.nextLeftHandle += padding.PadWidth(); handlePoint.nextTopHandle += padding.PadHeight(); // Debug.LogWarning("実験した方が良さそう"); } // Debug.LogError("rectTransform.anchoredPosition:" + rectTransform.anchoredPosition); /* * set next left-top point by parent tag kind. */ switch (parent.tag) { default: { // 回り込みを実現する。んだけど、これはどちらかというと多数派で、デフォルトっぽい。 // next content is planned to layout to the next of this content. handlePoint.nextLeftHandle = this.rectTransform.anchoredPosition.x + this.rectTransform.sizeDelta.x + this.padding.PadWidth(); // right edge with padding // Debug.LogError("handlePoint.nextLeftHandle:" + handlePoint.nextLeftHandle); break; } // Rootコンテンツにぶらさがっている項目は、全てCRLFがかかる。 case Tag.ROOT: { // CRLF handlePoint.nextLeftHandle = 0; handlePoint.nextTopHandle += this.rectTransform.sizeDelta.y + this.padding.PadHeight(); // Debug.LogError("親がRootなので、改行する。handlePoint.nextTopHandle:" + handlePoint.nextTopHandle + " of tag:" + tag + " rectTransform.anchoredPosition:" + this.rectTransform.anchoredPosition); break; } } return(handlePoint); }