# gSetAttribute

Definition: | include xpGUI.e gSetAttribute(gdx id, string name, object v, sequence args={})
Description: | Sets an interface element attribute. id: Identifier(s) of the interface element, may not be NULL, or contain any embedded NULLs. name: name of the attribute, usually a literal string such as "SIZE", several more examples below. v: value of the attribute. If NULL the default setting will be used (at least in most cases). args: (optional) if not {} then v = sprintf(v,args) is performed.
pwa/p2js: | Supported.
Comments: | Note that, unlike say gSetHandler[s](), the "with-s" version of this routine, ie gSetAttributes(), has a different purpose/api, being multiple attributes in one string, the common implementation of inlined attributes as part of most interface element creation routines, and in fact invokes this routine multiple times, whereas this "without-s" version sets a single attribute, potentially to a non-string value, and with both being able to apply said to one or more elements. When args is not {}, the implicit sprintf obviously crashes when v is not string, contains bad format specifiers, etc. Otherwise v can be anything, including integer, atom, string, [nested] sequence, or an equivalent string representation, eg:
            integer w = 100, h = 180
            gSetAttribute(id,"SIZE",{w,h})
            gSetAttribute(id,"SIZE","%dx%d",{w,h})
            gSetAttributes(id,"SIZE=%dx%d",{w,h})
            gSetAttribute(id,"SIZE",{100,180})
            gSetAttribute({id},"SIZE",{100,180})
            gSetAttribute(id,"SIZE","100x180")
            gSetAttribute(id,"SIZE","{100,180}")
            gSetAttributes(id,"SIZE={100,180}")
            gSetAttributes(id,"SIZE=100x180")
(obviously that’s nine slightly different ways to achieve exactly the same thing, the first being the fastest, inlined like the last generally the neatest overall code.) You can also use the following near-aliases: gSetInt(gdx id, string name, integer i) gSetDouble(gdx id, string name, atom a) Apart from the tighter validation of the third parameter (on desktop/Phix only), and perhaps more crucially a clearer declaration of intent which can help make the code a bit more self-documenting, they behave identically to gSetAttribute(). Since JavaScript is a typeless language, under pwa/p2js, there isn’t actually any additional validation (not that I’d struggle to add some), and for now they really are just pure aliases. [While there is a gGetIntInt(), there is no gSetIntInt(), as yet.] For boolean attributes gToggleInt(id,"NAME") can be used instead of gSetInt(id,"NAME",not gGetInt(id,"NAME")).
Example 1: |
    gSetAttribute(dlg, "VISIBLE", true) -- (and/or "YES"/"NO")
    gSetAttribute(text, "VALUE", "Hello!")
Example 2: |
    -- Enable or disable several buttons and/or menu entries simultaneously
    gSetAttribute({b_cut,b_copy,m_cut,m_copy}, "ACTIVE", selected_text!={})
See Also: | gSetHandler, gGetAttribute, gSetAttributes, gSetGlobal, gGetGlobal
Common: | The following attributes are common to several controls/interface element types. See also gGetAttribute for some other common read-only attributes.
ACTIVE | (inherited) Activates or inhibits user interaction. Value true/"YES" (active), false/"NO" (inactive). Default: true. An interface element is only active if its native parent is also active. ACTIVE can also be set for non-interactive controls and may affect their visual feedback. Affects: All controls that have visual representation.
BGCLR | The interface element’s background color, eg XPG_WHITE. If not specified, the native colour from the underlying backend (GTK/WinAPI/HTML) is used. On a gCanvas this is used to clear before each REDRAW, and hence should be set outside that handler. The aliases BGCOLOR and BGCOLOUR can also be used. Affects: Currently only gCanvas and gText. See also: FGCLR
CANFOCUS | Enables the focus traversal of the control. Defaults: true for gButton, gCheckbox, gDatePick, gDropDown, gList, gSlider, gSpin, gText, gTreeView, false for gCanvas, gGraph, gLabel, gProgressBar, gTable, and gDialog, gH/Vbox, gFrame, gSplit, gTabs. Obviously there should be no problem disabling anything in the first set, but no official support for enabling it on anything in the second set, except for gTable. It is assumed that most tables are likely to be read-only and there is no generic practical way to use the keyboard to perform things like column resize or column sort. Using specially designated/dedicated keystrokes such as <Ctrl [Shift] PgUp/Down> to switch between tabs is always going to be better than trying to use the keyboard on the control itself, likewise for said actions on a table. This setting has no influence whatsoever on an explicit gSetFocus() call.
EXPAND | Allows the element to expand, fulfilling empty spaces inside its container. It is a non inheritable attribute, but fairly obviously the overall behaviour depends on the expansion settings of both a container and its children. If expansion is disabled on a container then it gets a (fixed) minumum width/height that accomodates the largest of its children, none of the other children (including any sub-containers) being able to expand into anything beyond that. Should none of the children of a gH/Vbox expand in a given direction it can still expand but uses the SPACE attribute to distribute any excess and reposition the children appropriately. See also sole child. Value: "NONE"[/"N"/"NO"/"FALSE"/'N'/'F'/false/0], "BOTH"[/"B"/"YES"/"TRUE"/'B'/'Y'/'T'/true/1], "HORIZONTAL"[/"H"/'H'/2], or "VERTICAL"[/"V"/'V'/4] gGetAttribute(id,"EXPAND") returns one of the above (first) four strings, whereas gGetInt(id,"EXPAND") returns 0/1/2/4: and bits 0b011!=0 indicates horizontal expansion bits 0b101!=0 indicates vertical expansion. (ie 0b000 is N-one, 0b001 is B-oth, 0b010 is H-only, 0b100 is V-only, it is not a std bit-fld) Defaults: "NONE" for gButton, gCheckbox, gDatePick, gDropDown, gLabel, gProgressBar, gSlider, gSpin, gText, "BOTH" for gCanvas, gGraph, gList, gTable, gTreeView, and [gDialog], gH/Vbox, gFrame, gSplit, gTabs. Note that the natural size of a gCanvas, and hence all the (next three) canvas-based controls, is just the size of one character, and a gTreeView, with a natural size of {0,0}, is even smaller. Hence should you disable expansion on any of them you will almost certainly need to specify an explicit SIZE, that is unless the sole child rules prohibit/override the attempt to disable expansion. Affects: All elements, except menus and the gDialog itself. See also: MARGIN, GAP, SPACE, MINSIZE, MAXSIZE, RESIZE, Layout Management.
FGCLR | The interface element’s forground color, default XPG_BLACK. On a gCanvas this can be (transiently) overidden on each drawing operation instead. The aliases FGCOLOR and FGCOLOUR can also be used. Affects: Currently only gCanvas See also: BGCLR
FONT | (inherited) A string defining the font, in the format "<face>, <styles> <size>". Default: "Helvetica, 9". Since face names are not a standard between Windows and GTK, a few are specially handled to improve application portability:
Recommended | Windows | GTK | Description
--- | --- | --- | ---
Helvetica | Arial | Sans | without serif, variable spacing
Courier | Courier New | Monospace | with serif, fixed spacing
Times | Times New Roman | Serif | with serif, variable spacing
All nine fonts listed above work on any backend. Face names are case-sensitive and must exactly match those shown above. Fonts are automatically cached/pooled to minimise resource usage - note that gGetAttribute() returns the post-mapped platform-specific version. The font style can be omitted (aka normal) or a combination of: bold and italic (underline and strikeout are yet to be properly supported, but I can tell you they won’t ever be supported on a gCanvas). Optionally capitalised, ie/eg "bold" or "Bold". Font size is in points (1/72 inch) or in pixels (using negative values). [Technically optional, but no formal guarantee of what happens when omitted.] Examples:
        "Times, Bold 18"
        "Arial, 24" -- (no style)
        "Courier New, bold italic -30" -- (size in pixels)
Affects: All, except menus. See also JavaScript’s elem.style.fontXxx and ctx.font settings.
MARGIN | (not inherited) Specifies the initial spacing around any content. See Layout Management. Note margins are always handled by the parent container, and cannot be set on a gDialog (but can on the sole child). Specified as between one and four values: m or {m} or "m" => {m,m,m,m}, {tb,lr} or "tbxlr" => {tb,lr,tb,lr}, {t,lr,b} or "txlrxb"=> {t,lr,b,lr}, or {t,r,b,l} or "txrxbxl"[unchanged] The 1..4 integer values correspond to top, right, bottom, and left margins respectively/clockwise. Default: 0 (no margin). Returns: a sequence of length 1..4, or the atom 0 if not set. Affects: All elements except gDialog and menus. See also: GAP, SPACE, Layout Management.
? MAXSIZE, MINSIZE | (non inheritable) Specifies the element maximum/minimum size in pixels during the layout process. ?? Default: 0x0 (None), except for gDialog() and gFrame(), which get a default MINSIZE based on their TITLE at creation time. See Layout Management for more details on sizes. Value; "widthxheight", where width and height are integer values corresponding to the horizontal and vertical size, respectively, in pixels. You can also set only one of the parameters by removing the other one and maintaining the separator "x", but this is equivalent of setting the other value to 0. For example: "x40" (height only = "0x40") or "40x" (width only = "40x0"). Affects: All, except menus. On a gDialog also limits the interactive resize of the dialog, but does not override any explicit SIZE settings. See demo/xpGUI/gtk_fixed.exw for a [dialog] poc, same code does not currently work in xpGUI.e (with gUseGTK) presumably because it messes about with gtk_window_set_default_size and friends a bit too much or completely wrongly [fixes/suggestions welcome!] [MAXSIZE on a dialog does not work at all on GTK2, but you should not be using that in anger anyway.] See Also: SIZE
PADDING | Not yet implemented: the natural sizes of the four affected controls should be perfectly adequate for the first release. It may be that making SIZE center the contents is a better approach for those controls anyway. (not inherited, creation only) Similar in some respects to MARGIN, but only applicable to controls with a visible border (as listed below) and inside rather than outside that. Setting the padding automatically recalculates the USER_SIZE, and vice-versa in which case when PADDING is NULL (or {0,0,0,0}) it automatically centres the content, as per {tb,lr}. Default: 0 (no padding). [DEV that may not be quite true...] Returns: a sequence of length 1..4 (see MARGIN), or the atom 0 if not set. ? Affects: gButton, gDatePick, gDropDown, gText. (only) Since padding with no margin would behave exactly the same as margin with no padding on a gH/Vbox(), to keep itself simple xpGUI requires MARGIN be used. Likewise there is no padding on any container and hence the same (MARGIN) must instead be specified on the sole child of a gDialog() and gFrame(), while gSplit() and gTabs() both fairly adamantly opt out of all this. The error messages generated should very clearly indicate precisely what to do. See also: MARGIN, GAP, SPACE, SIZE, Layout Management.
TIP | (non inheritable, write-only) Text to be shown when the mouse is hovered over the element. Value: Text.
TITLE | The textual title/description of the interface element, often used to modify otherwise static text, such as that on a gButton, gCheckbox, gDialog, gFrame, gLabel, and maybe more. In most cases (except gDialog) the natural size is made large enough to include all the text in the selected font, even using multiple lines, plus things like the button/frame borders or the check box, if any. There is a completely unrelated GTITLE attribute on a gGraph, similar things are handled quite differently on gTable and gTabs (see links for detals), and the static text on menus is handled by gMenuSetAttribute() rather than this routine. Value: Text. Default: "" Notes The '\n' character usually is accepted for line change (except for menus, but they’re not handled here anyway). The "&" character can be used to define a MNEMONIC, use "&&" to show the "&" character instead of defining a mnemonic. If a mnemonic is defined such as "&File" then the 'F' is underlined and pressing <Alt F> activates the control. In some cases/platforms/backends the underline only appears while the Alt key is being held down. An automatic mapping of "&&","&","_" to "&","_","__" occurs under GTK, since that does mnemonics differently. Likewise HTML/JS/CSS uses (eg) <span class="malt">F</span>ile, though that is stripped when read back. Hence gGetAttribute(id,"TITLE") might not perfectly match that previously set, that is consistently between platforms/backends, and gSetAttribute(id,"TITLE",gGetAttribute(id,"TITLE")) or similar may have detrimental effects, on some. However, it should be fairly rare to ever fetch a static title, I would hope, since that cannot possibly ever be manually modified by the user anyway, but if you must, use say match("File",txt) rather than txt=="&File". Aside: I am not sure what this ever meant, and I’ve not deliberately put anything like this in, but I shall reproduce the following quote from the original IUP documentation: “For the benefit of GTK, should you define a mnemonic using "&" and the string has an underscore, then make sure that the mnemonic comes before the underscore”. I suspect but cannot be sure it is an outdated remark, from before "_"->"__", or some subtle buglette I have hopefully not accidentally managed to replicate. Note that gRedraw() may be required after changing the title for all characters to be shown. Affects: All elements with an associated text. See Also: FONT. Note that JavaScript’s elem.title implements TIP.
USER_DATA | A general storage slot: anything and everything which might be useful, especially in a handler routine, should and can safely be stored here. Can be set directly via the optional fourth parameter of a gTimer() on creation, as for other controls it should be set independently. Fairly obviously a leading '=' invocation of [inline] gSetAttributes() would be needed to set a non-string value. One word of caution: to avoid p2js violations an explicit nullification after fetch may be rqd/save a deep_copy(). Default: NULL.
? USER_SIZE | (implicit) Most applications should just do everything via SIZE, and pretend that USER_SIZE does not even exist. [There is indeed a valid argument this should not be made public, then.] Setting the SIZE attribute actually sets this instead, whereas reading that returns the actual size, though obviously reading this gets whatever was explicitly set (via SIZE or USER_SIZE), or {0,0} if not ever set, irrespective of whatever real size it might end up with. Note that both are affected by physically resizing or maximising/restoring the window, which automatically sets them to the same value, on a dialog anyway, whereas child elements typically get a SIZE based on the user|natural size after applying EXPAND, etc. Setting this is in fact indistinguishable from setting SIZE, and used by the layout manager as a starting point for recaclulating that. It should be obvious that we absolutely need a permanent copy of any value explicitly set, otherwise things couldn’t possibly ever "shrink" back properly, and likewise quite helpful to stash whatever it actually ended up setting, somewhere, rather than trying to re-figure it out whenever asked/needed. In short, the layout manager takes the max(user,natural,min) size, possibly then normalised, and finally expanded (if applicable) to fill the parent container, and/or ignoring anything blatently far too small, in order to obtain the actual size. Hence this can (initially) behave somewhat like a MINSIZE, but without the permanent restrictions, and does not in contrast ever act remotely like a MAXSIZE. Returns: integer {width,height}. For more details see Layout Management. See Also: SIZE
VALUE | The current content or state of a control, see individual entries for details. Affects: gTabs (also VALUEPOS), gCheckbox, gDatePick, gDropDown (also VALINT), gList, gProgressBar, gSlider, gSpin, gText. Should you be looking for the value() builtin, obviously click on that link.
? VISIBLE | Shows or hides the element. Value: "YES" (visible), "NO" (hidden). Default: "YES" Notes: An interface element is only visible if its native parent is also visible. Affects: All controls that have visual representation, except menus.
Technicalia | While pGUI had all manner of convoluted restrictions on attributes, such as v being atom_string or the dire distinction between IupSetAttribute() and IupSetStrAttribute(), largely because C and C-based languages cannot distinguish between an integer and a string (aka char*) 1, this one routine (gSetAttribute) covers and replaces at least 5 and probably more pGUI routines, even technically things such as IupSetInt() - while there is a gSetInt() as noted above, you can pass the exact same parameters direct to gSetAttribute(). As well as not replicating that particular distinction, xpGUI either actions things immediately or makes a (reference counted) copy, so (unlike pGUI) there is no danger here of a value "vanishing" before it can be used. Appropriate care may still sometimes be required with some values, such as a raw memory address, which must fairly obviously remain valid for the entire lifetime of the interface element, or at least until all copies/references to it are replaced. 1 Of course Phix manages that via a combination of limiting integers to 31/63 bits, storing 32/64 bit "integers" in an atom, and not having or depending on a pointer type, rather you store pointers in an atom and it becomes your sole responsibility to use them as such, for instance the language itself would not raise an eyebrow should you ask for the square root of a pointer, or for that matter use the pointer itself when you should be using whatever it points at. One Phix would catch is char* vs string, which are of course the exact same thing in C. Swings and roundabouts, I guess, the simple point being made is just that C and Phix have some rather fundamental differences, which certainly bleed through here.