carousel — u_pbt_carousel #
← Component reference · Guide contents
carousel leafs through items, only one of which is in front: the Cover Flow of iTunes — the current item face on, its neighbours turned in perspective and overlapping, a reflection under them —, a flat strip where several items show in full, a stack of cards, or a full-surface banner that shows one item at a time. Each item is a picture, a rich text or a card (picture, title, subtitle, body written by a template, tags, badge). The user clicks a neighbour, swipes with inertia, turns the wheel, types the first letters of a title or uses the keyboard;
ue_current_changedtells you which item is in front. The carousel is filled by hand or from a DataStore, and can move on by itself, with a PAUSE button.
▶ See it live — Demo application, Carousel tile: the preview, the code behind it and this page, side by side.
At a glance #
| Userobject | u_pbt_carousel |
| Item class | n_pbt_carousel_item (of_item(key)) |
| Used for | Leafing through album covers, products, photos, records, news or onboarding steps |
| Principle | An item has a unique key; only one is in front at a time, and it is drawn as a picture, a text or a card |
| Opt-in options | ib_veto_changes, ib_loop, ib_reflection, il_autoplay_ms |
| Demo mode limit | The first 6 visible items drawn — see demo mode |
Quick start #
// Three album covers : a key, a title, a picture
uo_covers.of_add_item(/*key*/ "c1", /*title*/ "Northern Lights", /*image*/ "img\packimages.dll:SVG/COVERS/COVER-01")
uo_covers.of_add_item(/*key*/ "c2", /*title*/ "Blue Hour", /*image*/ "img\packimages.dll:SVG/COVERS/COVER-02")
uo_covers.of_add_item(/*key*/ "c3", /*title*/ "Evergreen", /*image*/ "img\packimages.dll:SVG/COVERS/COVER-03")
// A reflection under the covers, as on a glossy floor
uo_covers.ib_reflection = true
// event ue_current_changed of uo_covers : (string as_from_key, string as_key)
// The album now in front, in the title of the window ("" : the carousel is empty)
if as_key <> "" then Parent.Title = this.of_item(/*key*/ as_key).is_title
Four layouts, three faces #
is_style chooses the layout: STYLE_COVERFLOW (the default) puts the current item face on and turns its neighbours in perspective, overlapping, spread over the width available and darker with the distance (ii_angle, ii_spacing, ib_shade); STYLE_CAROUSEL lines up a flat strip where several items show in full; STYLE_STACK piles up cards — the current one in front, the next ones behind it, the previous ones gone to the side; STYLE_HERO shows one item on the whole surface, the next one sliding or fading in (is_transition): the banner of a dashboard. A tile keeps a proportion (is_item_ratio; empty: 1:1 for pictures, 3:4 for cards, 16:9 for texts) and the content of a card or a text follows its size, between a readable floor and a ceiling. ib_reflection puts a reflection under the items, ii_item_width and ii_item_height set the size to the pixel.
Why faces rather than components inside the carousel? Every component of the library is a control of its own, with its own web page (a WebView2): it cannot sit inside the page of another one. So the carousel draws by itself what a picture, a statictext or a kanban card would show — these are the three faces of one item, and a thousand items cost one single control. is_item_style chooses the face of every item, is_style of an item chooses its own (empty: it follows the carousel). With ITEM_AUTO (the default), the face follows from what the item holds:
- a card template set (
is_card_template), or tags, or both a picture and a text → a card; - a picture → an image, which fills the tile (
is_fit); its title and its subtitle become the caption right under it, its badge stands over its corner; - a text alone → a text: rich text markup on a themed panel, like a statictext; an
[action=x]zone raisesue_action_clicked; - nothing but a title → a card.
of_item(key).of_face() tells the face chosen. A picture is a file of the workstation, a resource file.dll:name, a mono: or tint: glyph drawn in the theme, or an https:// address; an http:// address is refused and raises ue_image_failed with REASON_INSECURE, a missing file with REASON_NOT_FOUND.
// The covers as a pile of cards, the whole picture in each tile
uo_covers.is_style = u_pbt_carousel.STYLE_STACK
uo_covers.is_fit = u_pbt_carousel.FIT_CONTAIN
// This item is a card, whatever it holds
uo_covers.of_item(/*key*/ "c2").is_style = u_pbt_carousel.ITEM_CARD
A row aligned at its start #
On a flat strip (STYLE_CAROUSEL), is_align = ALIGN_START gives the row of a video service: the items stand from the start edge (the right one, right to left), every one whole and level, and the last screen is full — no empty room after the last item; an item cut by an edge invites to scroll. The current item is no longer in the middle: it is the one the user chose, always whole on the screen. The arrows and Page Up / Page Down move a screen (the items it shows whole) and the current item becomes the first one the screen brought; the arrow keys move one item and scroll just enough to keep it whole; the wheel and a swipe scroll and rest on a whole item, the current item following only when it would leave; a click on a whole item makes it current and raises ue_item_clicked. The arrows live in the margins, show only under the pointer or with the keyboard, and are gone at an end. The dots count screens (a dot is a place the strip can rest on); the counter still counts items. The autoplay moves a screen and, at the end, the first screen comes back from the side. With ib_loop, the row goes round when it is long enough to go round the screen (about three items more than it shows). ALIGN_START has no effect on the other layouts.
// The row of a video service : the covers from the start edge, a screen at a time
uo_covers.is_style = u_pbt_carousel.STYLE_CAROUSEL
uo_covers.is_align = u_pbt_carousel.ALIGN_START
// Small covers : the row holds several screens
uo_covers.ii_item_height = 150
The item in front #
The current item is the one in front; of_current_key() reads its key live. A click on a neighbour brings it in front; a click on the item in front raises ue_item_clicked, a double click (or Enter) ue_item_opened. A change of the user — click, keyboard, wheel, swipe, dot, arrow, autoplay — and a change of your code (of_select_item, of_next, of_previous) raise the same ue_current_changed, as SelectItem raises the event of the click. With ib_veto_changes, ue_current_changing is asked first, in both cases: returning FALSE leaves the item in front, and of_select_item then returns -4. ue_current_changed is raised too when the item in front leaves (hidden, removed: the nearest takes its place) and when the first item arrives in an empty carousel (as_from_key empty). An order of your code inside ue_current_changing (another item selected) wins: the answer that follows changes nothing any more. of_select_row brings the item of a row in front and of_current_row reads the row of the item in front; with ib_sync_row, the DataWindow given to of_from_datastore follows the item in front — the master-detail of a DataWindow.
A greyed item (ib_enabled = false) stays in its place, but the user can neither bring it in front nor click it: the keyboard, the wheel, Page Up / Page Down, the scrollbar and a throw jump over it; your code still selects it. A hidden item (ib_visible = false) leaves the carousel and keeps its key and its place. With ib_loop (three items at least), the first comes after the last. A double click on a neighbour brings it in front and stops there: neither ue_item_clicked nor ue_item_opened. il_autoplay_ms makes the carousel move on by itself, every so many milliseconds (500 at least): a PAUSE / PLAY button shows under it (ib_autoplay_button) and the user's pause holds until PLAY (of_pause, of_play, ue_autoplay_changed); it also stops for a moment under the pointer, while the keyboard is in the component and while the carousel is hidden. At the end of a carousel that does not loop, the first item comes back from the side. Every step goes through ue_current_changing like a gesture: a refused item is skipped, the next one is asked. A screen reader is not told every step while it plays.
Cards and caption written by template #
A card shows its picture on top, its title (is_title), its subtitle (is_subtitle), its body (is_text), its tags (is_tags, separated by commas, coloured by is_tag_tones: New=success|Sale=danger) and a badge (is_badge). The body of every card can be written by a template, is_card_template, and the caption under the carousel by is_caption_template: rich text markup where {price} is a field of the item — one of yours (of_set_field), a column of the DataStore it came from, or a built-in field (key, title, subtitle, text, image, badge, tags, position, count). {position} and {count} count the items drawn, as the counter does. {sold:dd/mm/yyyy hh:mm} writes a date or a date-time, {price:#,##0.00} a number: the display formats of a DataWindow column (mm after an hour = the minutes, [shortdate], [longdate], [time], sections positive;negative;zero), in the display language — a value the format cannot write is shown as it is. {?x}…{/x} keeps a piece when the field says something, {!x}…{/x} when it says nothing, {{ }} are braces. A value is shown as it is, never read as markup; {x:raw} keeps it as markup — keep it for your own fields: on a database column it would read the data as markup, action zones included. {title}, {subtitle}, {text} and {badge} written by your code are markup, as in the caption; read from a column, text.
// A price, a field of our own, then the body of every card
uo_shop.of_set_field(/*key*/ "p1", /*field*/ "price", /*value*/ "$12.90")
uo_shop.is_card_template = "{?price}From [b]{price}[/b]{/price}{!price}Price on request{/price}"
// Under the carousel : the place of the item in front, then its title
uo_shop.is_caption_template = "{position} / {count} - [b]{title}[/b]"
From a DataStore #
of_from_datastore makes one item of each row of a DataStore, a DataWindow or a DataWindowChild — the same call. Its key is the RowID of the row — it names its row as long as the DataStore is neither emptied nor read again (Reset, Retrieve and ImportString give the RowIDs 1, 2, 3 again), and of_item(key).of_row() finds it — or the value of the ROLE_KEY column, the key to give as soon as you refresh. A row whose key is empty, not valid, already met or held by an item added by hand is not loaded: the call returns 0 and of_get_last_error names it — give your hand items keys that are not numbers. A column plays a role when it is named like it (key, title, subtitle, text, image, badge, tags, color) or when of_map says so; the ROLE_COLOR column (an RGB() or #rrggbb) paints the stripe of a card. of_map and of_reload_row update the items in place (flags, fields, handle and place stay). A second load too, with ROLE_KEY: an item whose key comes back keeps its flags, its fields and its handle. Without ROLE_KEY, a second load is a new epoch: a RowID that comes back may name another record, every item of the rows is made anew (nothing is inherited, the handles of the old ones are freed) and, if the key in front comes back, ue_current_changed says it with as_from_key = as_key. Either way, the items take the order of the rows (an of_move_item does not survive a load), the items of the rows gone leave, those added by hand stay, after the rows; an item of a row removed by of_remove_item comes back with its row — hide it instead (ib_visible). Dates are read in the regional order of the workstation, numbers are written with a point, CHAR values without their padding, at a load as after of_reload_row. What a column gives is text, never markup — an [action=x] coming from the database is not clickable —, and a picture of a column never reaches a network path (\\server\share: ue_image_failed with REASON_UNC). When the ROLE_KEY column of a reloaded row changed, the item takes the new key: the handle of the old one is freed. Every column is a field of the templates.
// The rows of the albums : columns named title and subtitle play their role
ids_albums.Retrieve()
// The picture is in a column with another name
uo_covers.of_map(/*role*/ u_pbt_carousel.ROLE_IMAGE, /*column*/ "cover_file")
// One item per row, its key the RowID of the row
uo_covers.of_from_datastore(/*ads*/ ids_albums)
// Master-detail : the DataWindow follows the item in front, and the carousel reads its rows
uo_covers.ib_sync_row = true
uo_covers.of_from_datastore(/*adw*/ dw_albums)
// event rowfocuschanged of dw_albums : the item of the row comes in front
uo_covers.of_select_row(/*row*/ currentrow)
Properties #
| Property | Type | Default | Purpose | ||
|---|---|---|---|---|---|
is_style | string | STYLE_COVERFLOW | The layout: STYLE_COVERFLOW (the current item face on, its neighbours turned in perspective), STYLE_CAROUSEL (a flat strip, several items in full), STYLE_STACK (a stack of cards), STYLE_HERO (one item on the whole surface, a banner). Another value is refused: the old one stays, of_get_last_error says why | ||
is_item_style | string | ITEM_AUTO | The face of every item that does not choose one itself: ITEM_AUTO (from what it holds, see above), ITEM_IMAGE, ITEM_TEXT, ITEM_CARD. Another value is refused | ||
is_fit | string | FIT_COVER | How a picture fills its tile: FIT_COVER (the tile is full, the picture cropped) or FIT_CONTAIN (the whole picture). Another value is refused | ||
ib_reflection | boolean | false | A reflection under the items, as on a glossy floor | ||
ib_loop | boolean | false | After the last item comes the first (and before the first, the last). It needs three items at least | ||
il_autoplay_ms | long | 0 | Autoplay: the next item comes in front every il_autoplay_ms milliseconds (500 at least, a smaller value is brought up to it); 0 stops it. A PAUSE / PLAY button shows under the carousel (ib_autoplay_button); it also stops for a moment under the pointer, while the keyboard is in the component and while the carousel is hidden. At the end of a carousel that does not loop, the first item comes back from the side; an item ue_current_changing refuses is skipped | ||
ib_show_caption | boolean | true | The caption of the item in front: its title (and its subtitle), underlined with the accent, or what is_caption_template writes; it stands right under it or over its foot (is_caption_position) | ||
is_caption_position | string | CAPTION_AUTO | Where the caption stands: CAPTION_BELOW (right under the item in front, under its reflection when it has one), CAPTION_OVERLAY (over its foot, white on a dark veil), CAPTION_AUTO (under a picture — over its foot in a banner —, and none under cards or texts that already write their title, unless is_caption_template says what to write). Another value is refused | ||
ib_autoplay_button | boolean | true | A PAUSE / PLAY button under the carousel while il_autoplay_ms runs, and a thin bar that fills until the next item: whoever reads may stop what moves. The user's pause holds until PLAY; ue_autoplay_changed says it. false: no button | ||
is_indicator | string | INDICATOR_AUTO | What shows where we are, under the caption: INDICATOR_AUTO (dots up to 12 items, a scrollbar beyond), INDICATOR_DOTS (clickable dots, up to 48 items: beyond, the scrollbar), INDICATOR_SCROLLBAR (a bar to click and drag), INDICATOR_COUNTER (3 / 12), INDICATOR_NONE. Another value is refused | ||
ib_arrows | boolean | true | The two arrow buttons on the sides: the left one always goes left | ||
ii_item_width | integer | 0 | The width of a tile, in pixels (24 to 4000, a value outside is brought back inside); 0: from the size of the component and is_item_ratio. A width set with a height of 0: the height follows the proportion. No effect on STYLE_HERO: its item takes the whole surface | ||
ii_item_height | integer | 0 | The height of a tile, in pixels (24 to 4000); 0: from the size of the component, leaving the neighbours and the caption in sight. A height set with a width of 0: the width follows the proportion. No effect on STYLE_HERO | ||
is_item_ratio | string | "" | The proportion of a tile, width:height: "1:1", "3:4", "16:9"… The tile keeps it whatever the size of the component. Empty: from the face of most items — 1:1 for pictures, 3:4 for cards, 16:9 for texts. A value that is not two positive numbers joined by : is refused. No effect on STYLE_HERO | ||
ii_angle | integer | 62 | The turn of the covers on the sides of the Cover Flow, in degrees, from 0 (flat) to 80; 62 is the one of iTunes | ||
ii_spacing | integer | 100 | The spacing of the covers of the Cover Flow and of the tiles of a strip, in percent of what the carousel works out: 100 spreads the covers over the width available, 25 to 300 tightens or loosens them | ||
ib_shade | boolean | true | The covers on the sides darken with their distance, so that the item in front draws the eye; the cards waiting behind a stack too | ||
is_transition | string | TRANSITION_SLIDE | How a banner (STYLE_HERO) changes its item: TRANSITION_SLIDE (the next one slides in from the side) or TRANSITION_FADE (it fades in). Another value is refused | ||
is_align | string | ALIGN_CENTER | Where the current item stands on a strip (STYLE_CAROUSEL): ALIGN_CENTER (in the middle) or ALIGN_START (the row of a video service, aligned at its start edge, moving a screen at a time: see above). No effect on the other layouts. Another value is refused | ||
is_card_template | string | "" | The body of every card, written by a template (see above). Setting a template makes every ITEM_AUTO item a card. Empty: the text of the item (is_text) | ||
is_caption_template | string | "" | The caption under the carousel, written by a template (the same fields). Empty: the title, and the subtitle under it | ||
is_tag_tones | string | "" | The tone of each tag, tag=tone joined by ` | : New=success | Sale=danger. Tones: TONE_SUCCESS, TONE_WARN, TONE_DANGER, TONE_INFO (the accent), TONE_NEUTRAL`. A tag not listed, or an unknown tone, is neutral |
is_badge_format | string | "" | The display format of the badges that are a number or a date — a ROLE_BADGE column of the DataStore, or a value your code writes: "$#,##0.00", "dd/mm/yyyy", the format of a DataWindow column, in the display language. A badge that is neither (markup, a word) shows as it is. Empty: every badge as it is | ||
ib_sync_row | boolean | false | Master-detail: the DataWindow (or DataWindowChild) given to of_from_datastore follows the item in front — ScrollToRow on its row at every change, gesture or code. The other way round, call of_select_row from its RowFocusChanged. A DataStore has no row to show: nothing moves; an item added by hand has no row | ||
ib_veto_changes | boolean | false | Opt-in: ask ue_current_changing before every change of the item in front, of the user, of the autoplay and of of_select_item alike. The autoplay skips a refused item; the keyboard stays where it is — an item always refused is better greyed. An order of your code inside ue_current_changing wins: the answer that follows changes nothing. Off by default, like every cancelable event of the library | ||
ib_animated | boolean | true | The items slide to their new places. A workstation set to reduce motion jumps straight there, unless the application insists (PBT_SetAnimationPolicy) | ||
ii_anim_duration | integer | 450 | Duration of a move, in milliseconds (0 to 5000) | ||
is_anim_easing | string | EASING_EASE_OUT | The curve of the move: EASING_LINEAR, EASING_EASE_OUT, EASING_BACK_OUT (goes a little too far, then back), EASING_BOUNCE_OUT (bounces), EASING_ELASTIC_OUT (wobbles) | ||
ib_enabled | boolean | true | false greys the carousel out: the items stay shown, nothing answers the user any more (click, keyboard, wheel, swipe, autoplay) | ||
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change | ||
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change | ||
il_theme_accent | long | -1 | Accent colour of this component (-1 = the application accent, or the theme's) | ||
is_tooltip | string | "" | Simple tooltip shown when hovering the component | ||
is_super_tooltip_title | string | "" | Title of the rich tooltip (takes precedence over is_tooltip) | ||
is_super_tooltip_text | string | "" | Text of the rich tooltip (rich markup accepted) | ||
is_super_tooltip_image | string | "" | Image of the rich tooltip |
Properties of an item — n_pbt_carousel_item #
Its handle, through of_item(key). A read asks the carousel what it is now.
| Property | Type | Default | Purpose |
|---|---|---|---|
is_title | string | "" | Title of the item: the caption when it is in front, and the top line of a card. Accepts rich text markup. Empty, the item shows its key |
is_subtitle | string | "" | The second line, under the title of a card and of the caption (markup accepted). A picture with a subtitle stays an image: the subtitle goes to its caption |
is_text | string | "" | The text (markup accepted): the whole face of a text item, the body of a card while is_card_template is empty. An [action=x] zone raises ue_action_clicked on the item in front |
is_image | string | "" | The picture: a file of the workstation, a resource file.dll:name, a mono: / tint: glyph drawn in the theme, an https:// address. http:// is refused (ue_image_failed, REASON_INSECURE), and so is a network path from a DataStore column (REASON_UNC). A themed skeleton shows while the picture is on its way |
is_badge | string | "" | Small badge (markup accepted): a price, a count, in the accent — at the top right of a card, over the corner of a picture. A picture with a badge stays an image |
is_tags | string | "" | Tags of a card, separated by commas: Vinyl, Sale. Each one is a chip coloured by is_tag_tones of the carousel |
is_style | string | "" | The face of this item (ITEM_* of u_pbt_carousel); empty: it follows is_item_style of the carousel. Another value is refused: the old one stays, of_get_last_error of the carousel says why |
ib_visible | boolean | true | false takes the item out of the carousel; it keeps its key and its place. When it was in front, the nearest one takes its place (ue_current_changed) |
ib_enabled | boolean | true | false greys the item: the user can neither bring it in front nor click it, the keyboard and the wheel jump over it. Your code still selects it |
of_position ( ) → long | — | — | Returns the place of the item in the carousel now, counted from 1 (hidden items included); 0 when the carousel does not hold it |
of_row ( ) → long | — | — | Returns the row number today, in the rows given to of_from_datastore, of the row the item comes from — after a sort, a filter or the deletion of other rows, as long as the DataStore is neither emptied nor read again; 0 for an item added by hand or whose row is gone |
of_face ( ) → string | — | — | The face the item is drawn with now: "image", "text" or "card" (ITEM_IMAGE, ITEM_TEXT, ITEM_CARD) — what is_style chose or what ITEM_AUTO worked out; empty when the carousel does not hold it |
is_tooltip | string | "" | Simple tooltip shown when hovering the item |
is_super_tooltip_title | string | "" | Title of the item rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Text of the item rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the item rich tooltip |
il_accent | long | -1 | Accent of the item: the stripe at the top of a card (which it brings up) and of a text panel, and the badge, take it; it wins over the colour of a ROLE_COLOR column. The dots and the caption keep the accent of the component. -1 = the one of the component |
il_back_color | long | -1 | Background of a text or card face, as RGB(r,g,b) (-1 = what the theme gives). An image face has no background |
il_text_color | long | -1 | Text colour of a text or card face (-1 = what the theme gives) |
il_back_color_hover | long | -1 | Background of a text or card face under the pointer, in RGB(r,g,b) (-1 = its usual background). Nothing moves on hover : only the colour changes |
il_text_color_hover | long | -1 | Text colour of a text or card face under the pointer (-1 = its usual colour) |
Three reads of the handle, read only: of_position() returns the place of the item counted from 1, of_row() the number of its row in the DataStore (0 for an item added by hand), of_face() the face chosen. An item moves through of_move_item of the carousel.
Methods #
| Method | Purpose | |
|---|---|---|
of_add_item (string as_key, string as_title) | Adds an item at the end of the carousel, a title alone (a card): its picture, text, subtitle… are set on its handle. Its key is unique in the carousel. The first item of an empty carousel comes in front (ue_current_changed). Returns 0 once added, -5 for an empty key, one holding / or ` | , starting with __, or already taken (an item of a DataStore included), -2` when the component is not created |
of_add_item (string as_key, string as_title, string as_image) | The same with its picture. With ITEM_AUTO, a picture and a title alone make an image item, the title as its caption. Returns 0 once added, -5 as above, -2 when the component is not created | |
of_clear ( ) | Empties the carousel: items (those of a DataStore included) and their handles; the DataStore stays bound for a new of_from_datastore, the options stay. ue_current_changed follows, with an empty key, when an item was in front. Returns 0 once applied, -2 when the component is not created | |
of_current_key ( ) | The key of the item in front, whoever brought it there; empty when the carousel is empty. Read live | |
of_current_row ( ) | The row number today, in the rows given to of_from_datastore, of the item in front — after a sort, a filter or the deletion of other rows. Returns 0 when the carousel is empty, when the item in front was added by hand or its row is gone | |
of_from_datastore (datastore ads) | Makes an item of each row of the DataStore (see above). A second load updates the items in place with ROLE_KEY, makes them anew without it (a new epoch: nothing is inherited); those of the rows gone leave (handles freed), those added by hand stay, after the rows; a row not loaded is named by of_get_last_error. Returns 0 once loaded, -5 when the DataStore is not valid, -2 when the component is not created | |
of_from_datastore (datawindow adw) | The same from the rows of a DataWindow, read through a DataStore that shares them (ShareData). Returns 0 once loaded, -5 when the DataWindow is not valid or refuses to share its rows (of_get_last_error says it), -2 when the component is not created | |
of_from_datastore (datawindowchild adwc) | The same from the rows of a DataWindowChild (a drop-down DataWindow, a nested report). Returns 0 once loaded, -5 when it is not valid, -2 when the component is not created | |
of_get_field (string as_key, string as_field) | Reads a field of an item, live: one of yours, a column of its DataStore or a built-in field (title, position, count…). An empty string when it has none | |
of_get_last_error ( ) | Why the last call went wrong: a method that returned -5 or -4, a value refused (is_style, is_item_style, is_indicator, is_fit, is_caption_position, is_transition, is_item_ratio, is_align, is_style of an item), a call made during a wait (nothing could be judged), the rows a load left out. Emptied by every method that acts (a read leaves it); otherwise the last error of the library | |
of_insert_item (string as_key, string as_title, string as_image, long al_position) | Adds an item at a place counted from 1 (past the last one: at the end). The item in front stays in front. Returns 0 once added, -5 like of_add_item, -2 when the component is not created | |
of_is_playing ( ) | TRUE while the autoplay plays: il_autoplay_ms is set and nobody pressed PAUSE (a pointer over the carousel suspends it for a moment: it still plays). Read live | |
of_item (string as_key) | Returns the handle of an item (created on first access, freed when the item is removed) | |
of_map (string as_role, string as_column) | Gives a column of the DataStore a role when its name does not say it (ROLE_KEY, ROLE_TITLE, ROLE_SUBTITLE, ROLE_TEXT, ROLE_IMAGE, ROLE_BADGE, ROLE_TAGS, ROLE_COLOR). Before or after of_from_datastore: after, the rows are read again in place. An empty column gives the role back to the column named like it; a new ROLE_KEY gives the items new keys (the handles of the old ones are freed). Returns 0 once set, -5 for an unknown role or a column the DataStore does not have, -2 when the component is not created | |
of_move_item (string as_key, long al_position) | Moves an item to a place counted from 1 (past the last one: the last). The item in front stays in front. Returns 0 once moved, -5 for an unknown item, -2 when the component is not created | |
of_next ( ) | Brings the next item in front (the greyed ones skipped; after the last, the first with ib_loop), like the arrow key toward it (Right, Left right to left), and raises ue_current_changed. Returns 0 once done (also at the end: nothing moves, nothing is raised), -4 when ue_current_changing refused, -5 during a wait (nothing could be judged), -2 when the component is not created | |
of_pause ( ) | Pauses the autoplay, like the PAUSE button: the item in front stays until of_play (or PLAY). ue_autoplay_changed follows — an order of the code raises it like the button. Returns 0 once paused (also when it already is: nothing is raised), -5 when il_autoplay_ms is 0, -2 when the component is not created | |
of_play ( ) | Plays the autoplay again after a pause — the user's PAUSE button or of_pause. ue_autoplay_changed follows. Returns 0 once playing (also when it already plays: nothing is raised), -5 when il_autoplay_ms is 0 (nothing to play), -2 when the component is not created | |
of_previous ( ) | Brings the previous item in front, like the arrow key toward it. Returns 0 once done (also at the start: nothing moves, nothing is raised), -4 when ue_current_changing refused, -5 during a wait, -2 when the component is not created | |
of_reload_row (long al_row) | Sends a row of the DataStore of of_from_datastore to the carousel again, read now, after your code changed it (SetItem, an edit window); its item is updated in place (flags, fields, handle and place stay). A row the carousel does not hold yet (InsertRow) arrives after the last row item. When the ROLE_KEY column of the row changed, the item takes the new key: the handle of the old one is freed and, if it stood in front, ue_current_changed says it. Returns 0 once sent, -5 when nothing is bound, the row does not exist or its key is empty, not valid or held by another item (of_get_last_error says it), -2 when the component is not created | |
of_remove_item (string as_key) | Removes an item and frees its handle; removing the item in front brings the nearest one in front (ue_current_changed). An item of a DataStore row comes back with its row (of_reload_row, a new load): hide it (ib_visible) or delete the row. Returns 0 once removed, -5 for an unknown item, -2 when the component is not created | |
of_reset ( ) | Empties the carousel, forgets the DataStore and puts every property back to its default. Returns 0 once applied, -2 when the component is not created | |
of_select_item (string as_key) | Brings an item in front, like a click: it slides there and ue_current_changed follows. With ib_veto_changes, ue_current_changing is asked first. A greyed item is selected too: greyed stops the user, not your code. Returns 0 once done (or already in front: nothing is raised), -4 when ue_current_changing refused, -5 for an item unknown or not drawn (hidden, beyond the demo cap), -2 when the component is not created | |
of_select_row (long al_row) | Brings in front the item of a row of the rows given to of_from_datastore — al_row is the row number today, whatever ROLE_KEY says: the master-detail of a DataWindow, called from its RowFocusChanged. Like of_select_item on its key: ue_current_changed follows, ib_veto_changes asks first. Returns 0 once in front (or already in front), -4 when ue_current_changing refused, -5 when nothing is bound, the row does not exist or made no item (left out by the load, removed, hidden, beyond the demo cap), -2 when the component is not created | |
of_set_field (string as_key, string as_field, string as_value) | Gives an item a field of your own, for the templates: {price}; it wins over a DataStore column of the same name. A field name: letters, digits and _, no leading digit. Returns 0 once set, -5 for an unknown item or a name that is not one, -2 when the component is not created |
Events #
| Event | Raised when |
|---|---|
ue_current_changed (string as_from_key, string as_key) | The item in front changed: a click on a neighbour, the keyboard, the wheel, a swipe, a dot, an arrow, the autoplay, or your code (of_select_item, of_next, of_previous). Also when the item in front leaves (hidden, removed: the nearest takes its place) when the first item arrives in an empty carousel (as_from_key empty), and when a new load without ROLE_KEY gives the key in front to another record (as_from_key = as_key). as_key empty: the carousel is empty. With ib_sync_row, the DataWindow bound already shows the row |
ue_current_changing (string as_from_key, string as_key) → boolean | Cancelable, asked before a change of the item in front, only when ib_veto_changes = true: gesture, autoplay and of_select_item (so of_next, of_previous). Returning FALSE leaves the item in front, and of_select_item then returns -4. By default: TRUE |
ue_item_clicked (string as_key) | The item in front was clicked (or Space pressed). A click on a neighbour brings it in front instead (ue_current_changed) — and a double click on a neighbour only brings it, without this event; an [action=x] zone raises ue_action_clicked instead; a greyed item raises nothing |
ue_item_opened (string as_key) | A double click on the item in front, or Enter: open it. A double click on a neighbour only brings it in front |
ue_item_rclicked (string as_key, long al_x, long al_y) | A right click on an item, or the context-menu key (or Shift + F10) on the item in front. al_x, al_y are screen pixels; for a PowerBuilder menu, PopMenu(PointerX(), PointerY()) of your window |
ue_action_clicked (string as_key, string as_action) | An [action=x] zone of the text of the item in front was clicked: as_action = "x" |
ue_autoplay_changed (boolean ab_playing) | The autoplay was paused (ab_playing = false) or played again (true): the PAUSE / PLAY button under the carousel, or your code (of_pause, of_play raise it too). A pointer over the carousel suspends it without raising it |
ue_image_failed (string as_key, string as_reason) | The picture of an item could not be shown: as_reason is REASON_INSECURE (an http:// address), REASON_UNC (a network path from a DataStore column, refused before any request) or REASON_NOT_FOUND (file not found). Said once per item and picture |
ue_ready ( ) | The component has finished loading; everything sent beforehand has been replayed |
ue_runtime_missing ( ) | The WebView2 runtime is missing: the component stays empty |
ue_bg_color (long al_color) | The component has computed its theme background color; the userobject has already adopted it (backcolor) |
Keyboard and mouse #
- Click on a neighbour: it comes in front; on the item in front:
ue_item_clicked; double click:ue_item_opened(on a neighbour: it comes in front, nothing else); right click:ue_item_rclicked. - Drag or swipe: the strip follows the pointer; when let go, its speed carries it a few items further. Without
ib_loop, the ends are elastic. Let go outside the carousel, the drag still ends. - Wheel: it follows its speed — a notch, one item; a big turn, several; a touchpad adds its small steps up.
- Left / Right: the previous item, the next one — inverted in a right-to-left application; Up / Down: the same; Home / End: the first, the last; Page Up / Page Down: by as many items as the stage shows. Greyed items are skipped, everywhere.
- The first letters of a title bring it in front (case and accents ignored); the same letter again goes to the next one that starts with it.
- Enter:
ue_item_opened; Space:ue_item_clicked; context-menu key or Shift + F10:ue_item_rclickedon the item in front. - The side arrows (
ib_arrows, in their gutters: they cover no tile), the dots and the scrollbar (is_indicator) are clicked; the scrollbar is dragged too. The PAUSE / PLAY button (ib_autoplay_button) is clicked or reached with the keyboard. - The carousel is one stop of the Tab key (two with the PAUSE button); a ring of the accent surrounds the item in front while the keyboard is in it.
Examples #
A product showcase #
// A flat strip : several products in full, a counter under it
uo_shop.is_style = u_pbt_carousel.STYLE_CAROUSEL
uo_shop.is_indicator = u_pbt_carousel.INDICATOR_COUNTER
// A product : a picture and a title, then a badge and tags (it becomes a card)
uo_shop.of_add_item(/*key*/ "p1", /*title*/ "Northern Lights", /*image*/ "img\packimages.dll:SVG/COVERS/COVER-01")
uo_shop.of_item(/*key*/ "p1").is_badge = "New"
uo_shop.of_item(/*key*/ "p1").is_tags = "Vinyl, Sale"
// The tone of each tag, and the price in the body of every card
uo_shop.is_tag_tones = "Vinyl=info|Sale=danger"
uo_shop.of_set_field(/*key*/ "p1", /*field*/ "price", /*value*/ "$12.90")
uo_shop.is_card_template = "From [b]{price}[/b]"
Asking before the item changes #
// Once : ask before the item in front changes
uo_covers.ib_veto_changes = true
// event ue_current_changing of uo_covers : not while the form beside it is not saved
if ib_unsaved then return false
return true
Opening an item of a DataStore in your window #
// Local variables
long ll_row
// event ue_item_opened of uo_covers : the row of the item, edited in a RESPONSE window (the code waits for it)
ll_row = uo_covers.of_item(/*key*/ as_key).of_row()
OpenWithParm(w_album_edit, ll_row)
// The row may have changed : the item follows it
uo_covers.of_reload_row(/*row*/ ll_row)
News that move on by themselves #
// A banner : one item on the whole surface
uo_news.is_style = u_pbt_carousel.STYLE_HERO
// Text items : rich text on a themed panel, with an [action] zone
uo_news.of_add_item(/*key*/ "n1", /*title*/ "Release")
uo_news.of_item(/*key*/ "n1").is_text = "[b]Version 5.0[/b] is out. [action=notes]Read the notes[/action]"
uo_news.of_add_item(/*key*/ "n2", /*title*/ "Webinar")
uo_news.of_item(/*key*/ "n2").is_text = "[b]Webinar[/b] on Thursday at 10:00."
uo_news.of_add_item(/*key*/ "n3", /*title*/ "Support")
uo_news.of_item(/*key*/ "n3").is_text = "[b]Support[/b] answers within one day."
// A new one every 5 seconds, faded in, the first again after the last :
// a PAUSE button shows under the banner
uo_news.is_transition = u_pbt_carousel.TRANSITION_FADE
uo_news.il_autoplay_ms = 5000
uo_news.ib_loop = true
// event ue_action_clicked of uo_news : (string as_key, string as_action)
// The zone [action=notes] of the first item opens the release notes
if as_action = "notes" then Open(w_release_notes)
A large catalogue #
// The products : one row = one item, its key the product code
ids_products.Retrieve()
uo_shop.of_map(/*role*/ u_pbt_carousel.ROLE_KEY, /*column*/ "code")
uo_shop.of_from_datastore(/*ads*/ ids_products)
// Only the tiles near the one in front are drawn : thousands of rows cost nothing.
// Beyond 12 items a scrollbar replaces the dots ; the user types a name to reach it
uo_shop.of_select_item(/*key*/ "P250")
Good practice #
- Pictures of the same proportions: the Cover Flow reads at a glance when the tiles have the same shape;
is_item_ratiosets it,FIT_CONTAINshows the whole picture. - Little text per face: a card reads in two lines, the detail goes into your window (
ue_item_opened). - A slow autoplay (four to six seconds), with its PAUSE button: whoever reads must be able to stop what moves.
- Keys that are not numbers for your hand items, in a carousel fed by a DataStore: an item keyed
12keeps the row of RowID 12 from being loaded (of_get_last_errorsays it). ROLE_KEYas soon as you refresh a DataStore (Retrieve,Reset): without it, a reload makes every item anew, since a RowID that comes back may name another record.- Many items cost nothing: only those within reach of the item in front are drawn, and a picture is loaded only when it comes near — the user reaches a title by typing it.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_count · of_keys_at · of_has | Walk what the component holds | 3.2 Items |
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |
is_accessible_name · is_accessible_description | The name and description a screen reader says | 3.4 Optional properties and events |
Two helpers are not inherited: of_icon and of_escape_markup live on n_pbt_utils. Declare one — n_pbt_utils lnv_utils, nothing to create — and call them on it.