/* XOWA: the XOWA Offline Wiki Application Copyright (C) 2012 gnosygnu@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package gplx.gfui.gfxs; import gplx.*; import gplx.gfui.*; import java.awt.font.TextAttribute; import java.text.AttributedString; import gplx.core.envs.*; import gplx.gfui.draws.*; import gplx.gfui.controls.gxws.*; import gplx.gfui.controls.elems.*; import gplx.gfui.controls.windows.*; public class GfxStringData { public String Val() { if (ownerElem == null) return val; if (ownerElem.TextVal() == null) return ""; return ownerElem.TextVal(); } String val = ""; public GfuiAlign AlignH() {return alignH;} GfuiAlign alignH; public GfxStringData AlignH_(GfuiAlign val) { alignH = val; if (ownerElem != null) Gfo_invk_.Invk_by_val(ownerElem, GxwElem_lang.AlignH_cmd, alignH); // needed for TextBox, since its Paint is not overriden TextRect_setNull(); return this; } public GfuiAlign AlignV() {return alignV;} public GfxStringData AlignV_(GfuiAlign val) {alignV = val; return this;} GfuiAlign alignV = GfuiAlign_.Mid; public ColorAdp Color() {return brush.Color();} public SolidBrushAdp UnderBrush() {return brush;} SolidBrushAdp brush; public AttributedString MnemonicString() {return mnemonicString;} AttributedString mnemonicString; String drawn = ""; public void MnemonicString_sync() { int pos = GfuiWinKeyCmdMgr.ExtractPosFromText(this.Val()); if (pos == String_.Find_none) return; drawn = String_.MidByLen(this.Val(), 0, pos) + String_.Mid(this.Val(), pos + 1); // rebuild string without & mnemonicString = new AttributedString(drawn); mnemonicString.addAttribute(TextAttribute.FONT, font.UnderFont()); mnemonicString.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, pos, pos + 1); } public GfxStringData Color_(ColorAdp val) { brush = SolidBrushAdp_.new_(val); if (ownerElem != null) ownerElem.Core().ForeColor_set(val); TextRect_setNull(); return this; } public FontAdp Font() {return font;} FontAdp font; public GfxStringData Font_(FontAdp val) { font = val; if (!Env_.Mode_testing() && ownerElem != null) ownerElem.Core().TextFont_set(font); TextRect_setNull(); MnemonicString_sync(); return this; } public RectAdpF TextRect() {return textRect;} public void TextRect_set(RectAdpF val) {textRect = val;} public void TextRect_setNull() {textRect = RectAdpF.Null;} RectAdpF textRect = RectAdpF.Null; public RectAdpF TextRect_setX(int x) { textRect = RectAdpF.new_(x, textRect.Y(), textRect.Width(), textRect.Height()); return textRect; } @gplx.Internal protected SizeAdp OwnerSize() {return ownerSize;} public void OwnerSize_sync(SizeAdp val) { ownerSize = val; TextRect_setNull(); ownerElem.Core().Invalidate(); // NOTE: force redraw; this may be redundant in WINFORMS but needed in SWING especially when windowOpened causes resize; SWING seems to execute windowOpened -> resize -> paint -> componentResized } SizeAdp ownerSize = SizeAdp_.new_(20, 20); @gplx.Internal protected GxwElem UnderElem() {return owner.UnderElem();} public void DrawData(GfxAdp gfx) { if (textRect.Eq(RectAdpF.Null)) {textRect = TextRect_calc(gfx);} gfx.DrawStringXtn(this.Val(), font, brush, textRect.X(), textRect.Y(), textRect.Width(), textRect.Height(), this); } public void Text_set(String v) { if (this.Val() == v) return; if (ownerElem != null) { ownerElem.TextVal_set(v); if (owner.CustomDraw()) ownerElem.Core().Invalidate(); } else this.val = v; TextRect_setNull(); MnemonicString_sync(); } public RectAdpF TextRect_calc(GfxAdp gfx) { float[] sizeAry = gfx.MeasureStringXtn(drawn == "" ? this.Val() : drawn, font, this); float width = sizeAry[0], height = sizeAry[1], descent = sizeAry[2]; // if (String_.Eq("opal.gfds 0.0.1", this.Val())) { // Tfds.Write(this.Val(), alignH.Val(), (int)width, ownerSize.Width()); // } float x = GfuiAlign_.CalcInsideOfAxis(alignH.Val(), (int)width, ownerSize.Width()); float y = 0; int alignVVal = alignV.Val(); float ownerHeight = ownerSize.Height(); if (alignVVal == GfuiAlign_.Null.Val()) y = Int_.Min_value; else if (alignVVal == GfuiAlign_.Lo.Val()) y = height - descent; else if (alignVVal == GfuiAlign_.Mid.Val()) y = (ownerHeight - (ownerHeight - height) / 2);// - descent; // COMMENT: subtracting descent is theoretically correct, but practically results in text shifted up else if (alignVVal == GfuiAlign_.Hi.Val()) y = ownerHeight - descent; if (width > ownerElem.Core().Width()) width = ownerElem.Core().Width(); // clip to elem size or else text overflows; EX: tab buttons if (x < 0) x = 0; if (y < 0) y = 0; // occurs when text is larger than elem; do not allow negative values return RectAdpF.new_(x, y, width, height); } GfuiElemBase owner; GxwElem ownerElem; public static GfxStringData new_(GfuiElemBase owner, GxwElem ownerElem) { GfxStringData rv = new GfxStringData(); rv.brush = SolidBrushAdp_.Black; rv.alignH = GfuiAlign_.Left; rv.owner = owner; rv.ownerElem = ownerElem; // WORKAROUND:.NET: setting font on textBox causes odd selection behavior for MediaTimeBox rv.Font_(FontAdp.new_("Arial", 8, FontStyleAdp_.Plain)); // needed for TextBox, since its Paint is not overriden, and .Font property must be set return rv; } GfxStringData() {} public static final GfxStringData Null = null; }