Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

The Contraption Bazaar Sticky

A topic by Internet Janitor created Feb 28, 2023 Views: 13,128 Replies: 138
Viewing posts 21 to 35 of 35 · Previous page · First page
Developer

PSA: several of the above contraption definitions were impacted by changes in Decker 1.32, and have been updated accordingly. If you're working on a deck that contains any of them (bouncer, eye, bob, pulse, rotor, seekRotor, interior, popOut), please refer to the release notes for help migrating.

Developer(+3)

by request,

The Chat Contraption:

The chat contraption provides a scrolling view of static text clustered into "speech bubbles" as in the text messaging UIs of most phones which can be advanced or retracted one bubble at a time.

The .value attribute contains rich text describing the chat log. Messages should be separated by a blank line (i.e. two newlines; \n\n). If a message is "!left" or "!right", it will switch which side of the conversation ensuing messages appear on instead of being displayed. Remember, you can use any other rich text formatting you like, including fonts and inline images!


The contraption exposes read-only .hasnext and .hasprev attributes indicating whether there are previous messages or next messages to show, respectively. It also exposes functions .next[] and .prev[] for stepping through message history. Any time you change the contraption's .value attribute the history will be reset to show only the first message.

The contraption respects the standard .show and .font attributes to control the transparency mode and default font of the chat log.

This contraption is provided below along with an enclosing card and prev/next buttons for paging through messages, to demonstrate how to use .hasprev/.hasnext/.prev[]/.next[]; these buttons are not part of the contraption itself and therefore can be freely customized or replaced to suit the needs of a particular application:

%%CRD0{"c":{"name":"card1","script":"on view do\n prev.locked:!chat1.hasprev\n next.locked:!chat1.hasnext\nend","widgets":{"chat1":{"type":"contraption","size":[196,155],"pos":[176,77],"font":"menu","show":"transparent","def":"chat","widgets":{"f":{"size":[196,155],"show":"transparent","value":{"text":["i"],"font":[""],"arg":["%%IMG2ALAAHAAFAWkARQFtAEIBbwBAAXEAPwFxAD4BcwA9AQUgAgFsAD0BBSACAWwAPQEFIAUBAyAEAQIgAgECIAIBWgA9AQUgAgECIAIBASACAQIgAgEBIAIBAiACAVoAPQEFIAIBAiACAQEgAgECIAIBASACAQIgAgFaAD0BBSACAQIgAgEBIAYBASACAQIgAgFaAD0BBSACAQIgAgEBIAIBBSACAQIgAgFaAD0BBSACAQIgAgEBIAIBAyABAQEgAgECIAIBWgA9AQUgAgECIAIBAiAEAQMgBQFaAD0BFyACAVoAPQETIAEBAyACAVoAPQEUIAQBWwA9AXIAPgFyAD4BcQA/AXAAQAFuAP8A/wD/ALU="]}},"msg":{"size":[100,31],"pos":[225,11],"value":{"text":["hey\n\ncan you read these?\n\n!right\n\nyeah\n\nwhat's up\n\n...\n\ncome on, man, don't keep me hanging here forever\n\n!left\n\nsorry\n\nlooks like the chat contraption works\n\n!right\n\n","sweet!","\n\n!left\n\nkeep in mind that there's kind of a soft limit to how many messages we can display\n\n!right\n\ngot it\n\nsince the messages are updated in response to an attribute change we have to stay in quota\n\n!left\n\nexactly\n\nbut as you can see the limit is reasonably high for practical use\n\n!right\n\nyeah this isn't too bad\n\nwe could also try to use longer sentences, since the cost is per speech bubble rather than per character\n\n!left\n\ntruth\n\nanyway, hopefully this contraption is handy!"],"font":["","menu",""],"arg":["","",""]}},"idx":{"size":[100,31],"pos":[225,53]},"tmp":{"pos":[225,91],"font":"menu"},"cnt":{"size":[100,31],"pos":[225,110],"value":"18"}}},"next":{"type":"button","size":[60,20],"pos":[280,260],"script":"on click do\n chat1.next[]\n view[]\nend","text":"Next"},"prev":{"type":"button","size":[60,20],"pos":[202,260],"locked":1,"script":"on click do\n chat1.prev[]\n view[]\nend","text":"Prev"}}},"d":{"chat":{"name":"chat","size":[100,100],"resizable":1,"margin":[5,5,5,5],"description":"a semi-interactive scrollable chat log.","script":"on get_value   do msg.value end\non set_value x do msg.value:x idx.text:0 view[] end\n\non view do\n f.show:card.show\n tmp.font:card.font\n tw:(first f.size)-20\n mw:floor .6*tw\n d :0\n r :rtext.cat[]\n margin:4 take 5\n lborder:image[\"%%IMG0AAwADAYAH4A/wH/gf+D/8P/w/+D/4P/A/4D+AA==\"]\n rborder:image[\"%%IMG2AAwADAAFAQIACAECIAIBAgAFAQEgBgEBAAMBASAIAQEAAgEBIAgBAQABAQEgCgECIAoBAQABAQEgCQEBAAEBASAJAQEAAgEBIAgBAQADAQIgBgEBAAUBBw==\"]\n   \n each chunk in rtext.split[\"\\n\\n\" msg.value]\n  str:rtext.string[chunk]\n  if     \"!left\" ~str d:0\n  elseif \"!right\"~str d:1\n  else\n   mh:last tmp.textsize[chunk mw]\n   sz:mw,mh\n   tmp.size:tw,mh+15\n   tmp.clear[]\n   if d # right-half\n    tmp.segment[rborder ((tw-mw+10),0),(10+sz) margin]\n    tmp.pattern:1\n    tmp.text[chunk ((tw-mw+5),5),sz \"top_right\"]\n   else # left-half\n    tmp.segment[lborder (0,0,10+sz) margin]\n    tmp.pattern:32\n    tmp.text[chunk (5,5,sz) \"top_left\"]\n   end\n   r:r,rtext.cat[tmp.copy[]]\n  end\n end\n tmp.size:1,1\n cnt.text:count r\n i:1+0|idx.text\n r:i limit r\n f.value:r\nend\n\non get_animate do view end\non get_hasprev do (0+idx.text)>0          end\non get_hasnext do (0+cnt.text)>1+idx.text end\non get_prev do\n on prev do\n  if get_hasprev[] idx.text:idx.text-1 view[] f.scroll:9999999 end\n end\nend\non get_next do\n on next do\n  if get_hasnext[] idx.text:idx.text+1 view[] f.scroll:9999999 end\n end\nend\n","attributes":{"name":["value"],"label":["Value"],"type":["rich"]},"widgets":{"f":{"type":"field","size":[100,100],"pos":[0,0],"locked":1,"scrollbar":1},"msg":{"type":"field","size":[100,20],"pos":[129,7],"locked":1,"show":"none"},"idx":{"type":"field","size":[100,20],"pos":[129,34],"locked":1,"show":"none","value":"0"},"tmp":{"type":"canvas","size":[1,1],"pos":[129,59],"locked":1,"image":"%%IMG0AAEAAQA=","pattern":32,"scale":1},"cnt":{"type":"field","size":[100,20],"pos":[129,71],"locked":1,"show":"none","value":"1"}}}}}

A question: if I've used a richtext link in the chatlog is there any way to have the link be clickable?

Developer

No; unfortunately the way this contraption works requires rendering out every message as an inline image, which bakes links down into only their visual appearance (the dotted underline).

Ahh, no worries. That is pretty neat though!

(5 edits) (+5)

itemlist contraption

This contraption lets you store a list of items. Basically it wraps a two-column grid, but the second column is hidden and replaced with a big text area.

The buttons at the top do the following:

  • -> "run", passes the current text to a configurable event handler on the card (run_event attribute contains the event name to trigger). Using shift-enter with the editor focused will also trigger this event, either on the entire item text or the selection. 
  • up/dn -> moves the current item up or down in the list of items
  • </> -> lets you navigate between the items in order. (you can click the names in the list to do this, but you can also hide the names by setting the list_width attribute to 0) 
  • - -> deletes the current item (shows a confirmation box first)
  • + -> adds a new item

There are also two helper functions you can use to get access to the underlying data:

  • .ls[] -> returns the entire items.value table
  • .current[] -> returns the current row from the table.

<couldn't get the widget to paste correctly. see comment below for link to a .deck>

It looks like the code might've been pasted wrong? I tried importing it into my deck and it didn't load correctly. I would love it if this was fixed since it does exactly what I need!

(+2)

I can't seem to get the widget by itself to paste correctly. I tried uploading it to another site but it just comes back blank.
Meanwhile, I just uploaded an entire deck with nothing but the widget:
https://gist.github.com/tangentstorm/37a26ebf0dc438eae1e765675b73ecd0

(+1)

tysm!! Using this to have a database card in my character sheet for the TTRPG I play with my friends :D

(+2)

Would it be possible to use this as a base for a simple inventory system? Ie the user finds an "item" by clicking a button, causing the button to disappear and the item to be added to this contraption?

(1 edit) (+8)

dialogizer styler

A contraption to quickly generate style code snippets for Dialogizer. Get what you need then delete it when you're done.

%%WGT0{"w":[{"name":"dialogizer styler1","type":"contraption","size":[289,187],"pos":[49,48],"show":"transparent","def":"dialogizer styler","widgets":{"fontlist":{},"fct":{},"bct":{},"fclr":{"value":"47"},"bclr":{"value":"32"},"tft":{},"tfnt":{},"patpal":{},"traplist":{"row":18},"tbr":{},"brdr":{},"button1":{},"idi":{"value":"p"},"result":{},"sti":{}}}],"d":{"dialogizer styler":{"name":"dialogizer styler","size":[289,187],"margin":[0,0,0,0],"description":"generate style code","script":"on view do\nfontlist.value:select name:key from deck.fonts\nfprv.font:first fontlist.rowvalue\nfprv.text:first fontlist.rowvalue\ntfnt.font:first fontlist.rowvalue\ntfnt.text:first fontlist.rowvalue\ntraplist.value:select name:key from deck.contraptions\nbrdr.text:first traplist.rowvalue\nend","image":"%%IMG2ASEAuwD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wAUIQEA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wDZ","widgets":{"fontlist":{"type":"grid","size":[97,176],"pos":[96,11],"locked":1,"script":"on click row do\n view[]\nend","headers":0,"value":{"name":["body","menu","mono"]},"row":0},"fct":{"type":"field","size":[48,16],"pos":[0,11],"locked":1,"font":"mono","border":0,"align":"right","value":"fcolor:"},"bct":{"type":"field","size":[48,16],"pos":[0,25],"locked":1,"font":"mono","border":0,"align":"right","value":"bcolor:"},"fclr":{"type":"field","size":[49,16],"pos":[48,11],"font":"mono","border":1,"value":"32"},"bclr":{"type":"field","size":[49,16],"pos":[48,26],"font":"mono","border":1,"value":"47"},"tft":{"type":"field","size":[48,16],"pos":[0,40],"locked":1,"font":"mono","border":0,"align":"right","value":"tfont:"},"tfnt":{"type":"field","size":[49,16],"pos":[48,41],"border":1,"value":"body"},"patpal":{"type":"canvas","size":[288,10],"pos":[0,1],"locked":1,"border":0,"image":"%%IMG2ASAACiASARMhESISIxIkEiUSJhInEigSKRIqEisSLBItEi4SIBIBEyERIhIjEiQSJRImEicSKBIpEioSKxIsEi0SLhIgBAEEIAIBBCAEAQQgAQEFIAUBBCEDAQQhAgEEIQQiBAEEIgIBASIHIwQBBCMDAQMjBCQEAQQkAgEBJAclBAEEJQIBBSUDJgQBBCYDAQImBScEAQQnAgEEJwQoBAEBKAUBBCgEKQQBASkFAQMpBSoEAQEqBQEEKgQrBAEBKwUBBCsELAQBASwFAQEsBy0EAQEtBgEDLQQuBAEBLgUBAS4HIAcBASAFAQEgBAEEIAEBASABAQcgAQEEIQYBASEFAQEhBCIHAQEiAgEBIgEBASIFIwcBASMDAQEjBiQHAQEkAgEBJAclBwEBJQYBASUDJgcBASYDAQImBScHAQEnAgEBJwIBAScEKAQBASgBAQEoAwEBKAIBASgEKQQBASkBAQEpBQEBKQUqBAEBKgEBASoGAQEqBCsEAQErAQEBKwYBASsELAQBASwBAQEsAwEBLAEBASwFLQQBAS0BAQEtBAEBLQYuBAEBLgEBAS4DAQEuByAHAQEgBQEBIAQBBCABAQEgAQEHIAEBBCEGAQEhBQEBIQQiBwEBIgIBASIBAQEiBSMHAQEjAwEBIwYkBwEBJAIBASQHJQcBASUGAQElAyYHAQEmAwECJgUnBwEBJwIBBCcEKAQBASgBAQEoAwEBKAIBASgEKQQBASkBAQEpBQEBKQUqBAEBKgEBASoGAQEqBCsEAQErAQEBKwYBASsELAQBASwBAQEsAwEBLAEBASwFLQQBAS0BAQEtBAEBLQYuBAEBLgEBAS4DAQEuByAFAQIgAwEEIAQBBCADAQUgAgEFIQQBAiEEAQIhBSIFAQIiAwEDIgUjBQECIwQBAyMEJAUBAiQDAQQkBCUFAQIlBQECJQQmBQECJgMBBCYEJwUBAicGAQEnBCgEAQMoAwEBKAIBASgEKQQBAykFAQEpAQEBKQMqBAEDKgMBBCoEKwQBAysEAQIrBSwEAQMsAwEDLAUtBAEDLQQBAy0ELgQBAy4DAQQuBCAHAQEgAgEBIAcBBiABAQUgAQEGIQYBASEFAQEhBCIHAQEiBAEBIgUjBwEBIwUBASMEJAcBASQCAQEkAgEBJAQlBwEBJQQBASUFJgcBASYCAQEmAgEBJgQnBwEBJwUBAScEKAYBASgDAQEoAgEBKAQpBgEBKQUBASkBAQEpAyoGAQEqAwEBKgcrBgEBKwYBASsELAYBASwFAQEsBS0GAQEtBgEBLQQuBgEBLgMBAS4CAQEuBCAEAQQgAgEEIAQBBiABAQUgAQEGIQMBBCECAQQhBCIEAQQiBAEBIgUjBAEEIwIBBCMEJAQBBCQCAQQkBCUEAQQlBAEBJQUmBAEEJgIBBCYEJwQBBCcFAQEnBCgGAQEoAwEEKAQpBgEBKQMBBSkDKgYBASoDAQQqBCsGAQErAwEEKwQsBgEBLAUBASwFLQYBAS0DAQQtBC4GAQEuAwEELgQgEgETIREiEiMSJBIlEiYSJxIoEikSKhIrEiwSLRIuEiASARMhESISIxIkEiUSJhInEigSKRIqEisSLBItEi4S","scale":1},"traplist":{"type":"grid","size":[96,176],"pos":[192,11],"locked":1,"script":"on click row do\n view[]\nend","headers":0,"value":{"name":["dialogizer styler"]},"row":2},"tbr":{"type":"field","size":[48,16],"pos":[0,55],"locked":1,"font":"mono","border":0,"align":"right","value":"border:"},"brdr":{"type":"field","size":[49,16],"pos":[48,56],"border":1,"value":"dialogizer styler"},"button1":{"type":"button","size":[96,16],"pos":[0,89],"script":"on click do\nresult.text:\"%s:()\n%s.fcolor:%s\n%s.bcolor:%s\n%s.tfont:%s\n%s.border:deck.contraptions.%s\ndd.style[%s]\" format idi.text,idi.text,fclr.text,idi.text,bclr.text,idi.text,tfnt.text,idi.text,brdr.text,idi.text\nend","text":"generate","style":"rect"},"idi":{"type":"field","size":[49,16],"pos":[48,71],"font":"mono","border":1,"value":"o"},"result":{"type":"field","size":[97,80],"pos":[0,107],"script":"on change val do\n \nend"},"sti":{"type":"field","size":[48,16],"pos":[0,70],"locked":1,"font":"mono","border":0,"align":"right","value":"ID:"}}}}}
Developer(+2)

Feel like your life just isn't sliding into place? Experience catharsis with

ThatPuzzle Contraption

The ThatPuzzle contraption is a classic sliding tile puzzle often called a "15-puzzle", in contraption form. Configure its dimensions from 2x2 to 10x10 tiles, and it will automatically display an image sliced up from the card background it's placed over. There are even event hooks and attributes for recognizing a successful solution!

  • thatpuzzle.dim : r/w integer from 2 to 10; the number of tiles per axis.
  • thatpuzzle.solved: read-only bool; is the puzzle currently solved?
  • thatpuzzle.reset[] : reset the tiles to a solved configuration.
  • thatpuzzle.scramble[] : randomize the tiles. for large puzzles you may need to repeat this a few times for a thorough mixing.
  • on change do .. end : fired whenever a user moves a tile.
%%WGT0{"w":[{"name":"thatpuzzle1","type":"contraption","size":[100,100],"pos":[199,126],"script":"on change do\n won.value:me.solved\nend","def":"thatpuzzle","widgets":{"c":{},"s":{"value":"[]"},"dim":{"value":"3"}}}],"d":{"thatpuzzle":{"name":"thatpuzzle","size":[100,100],"resizable":1,"margin":[5,5,5,5],"description":"the classic sliding-tile puzzle. you know, that one.","script":"BG:image[\"%%IMG2AAYABgEIDQMBAiABAQENAgECIAIBBCACAQEMAQEH\"]\nFG:image[\"%%IMG2AAkACQEGAAMBASAEAQIAAgEBIAQBASABAQEAAQEBIAQBASACAQIgBAEBIAIBByACAQEAAQEBDQQBASABAQEAAgEBDQQBAgADAQY=\"]\nBG_M:4,4,1,1\nFG_M:4,4,4,4\nDELTAS:\"%j\" parse \"[[-1,0],[0,-1],[1,0],[0,1]]\"\nSTEPS:30\n\non get_dim do 0+dim.text end\non set_dim x do dim.text:10&2|x end\n\non swap a x y do t:a[x] a[x]:a[y] a[y]:t a end\non initstate do d:get_dim[] (d^2)%1+range d^2 end\non setstate x do s.text:\"%j\" format list x end\non getstate do\n d:get_dim[]\n r:\"%j\" parse s.text\n if (d^2)~count r r else initstate[] end\nend\n\non view do\n d:get_dim[]\n b:getstate[]\n cell:c.size/d\n c.segment[BG 0,0,c.size BG_M]\n o:d cross d\n tiles:select orderby p asc where v from select v:b p:o from ()\n each row in rows tiles\n  c.segment[FG (row.p*cell),(cell+2 drop FG_M) FG_M]\n  bg:deck.card.image.copy[card.pos+o[row.v-1]*cell (cell,cell)-1]\n  c.paste[bg (1+row.p*cell)]\n end\nend\n\non click pos do\n d:get_dim[]\n b:nb:getstate[]\n o:(d cross d) dict range d^2\n p:floor pos/c.size/d\n each delta in DELTAS\n  t:p+delta\n  if (0~b[o[t]])&(!max(t<0)|(t>d-1)) nb:swap[b o[t] o[p]] end\n end\n setstate[nb]\n view[]\n if !nb~b card.event[\"change\"] end\nend\n\non get_reset do\n on reset do\n  setstate[()]\n  view[]\n end\nend\n\non get_scramble do\n on scramble do\n  d:get_dim[]\n  b:getstate[]\n  o:(d cross d) dict range d^2\n  p:first extract key where 0=b from o\n  each in range 100\n   t:p+random[DELTAS]\n   if !max(t<0)|(t>d-1) b:swap[b o[t] o[p]] p:t end\n  end\n  setstate[b]\n  view[]\n end\nend\n\non get_solved do\n getstate[]~initstate[]\nend","template":"on change do\n \nend","attributes":{"name":["dim"],"label":["Dim"],"type":["number"]},"widgets":{"c":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"scale":1},"s":{"type":"field","size":[100,20],"pos":[117,13],"show":"none"},"dim":{"type":"field","size":[100,20],"pos":[117,47],"show":"none","value":"4"}}}}}

hi im adding an alert when get solved but its firing it every time it changes. where do i put alert when puzzle is complete only? thank you.

Developer (1 edit)

The ThatPuzzle contraption fires a "change" event every time a tile is moved, and exposes a ".solved" attribute that tests whether the current configuration is a correct solution. Thus, you should check the .solved attribute within a "change" event handler on the widget's script, like so:

on change do
 if me.solved
  alert["it's solved!"]
 end
end

thank you that worked great! I posted in the breakout game section too. thanks again.

(1 edit) (+3)

used the puzzle as a way to progress in noir game  THE MALTESE FALCON by RetroGamma  

Developer (1 edit) (+4)

Tired of having boring checkboxes? Tired of having a boring life? Spice things up with

The ToggleButton Contraption


The toggleButton contraption behaves as a drop-in replacement for a "checkbox"-styled button widget, using customizable graphics instead of a textual label. Just like a Button widget, this produces click[] events when clicked, exposes a boolean .value attribute, and respects .show for transparency. If provided with a single image, the image will be displayed only if the value is 1. Otherwise, the first image will be used to indicate a value of 0 and the last image will be used to indicate a value of 1. If images are smaller than the bounding box of the contraption, they will be drawn centered.

%%WGT0{"w":[{"name":"toggleSwitch","type":"contraption","size":[53,31],"pos":[155,141],"show":"transparent","def":"toggleButton","widgets":{"c":{"size":[53,31],"show":"transparent"},"b":{"size":[53,31]},"ims":{"size":[100,6],"pos":[74,2],"value":{"text":["","i","i"],"font":["","",""],"arg":["","%%IMG2ADMAHQAoAQIALwECIAIBAQAsAQIgBAECACkBAiAGAQIAJwECIAQNAiACAQEMAQEBAAgBHiAGDQIgAgEBDAEBBQADAQEgGQEDIAUNASACDQIgAgEBDAIBASADAQEAAQEBIBcBAyAHDQMgAQ0CIAIBAQwDAQEgAwECIAMBFCAHDQEgAg0GIAIBAQwDAQEgAwECIAIBFCAGDQQgAQ0GIAIBAQwEAQEgAgECIAIBAiAXDQUgAQ0GIAIBAQwEAQEgAgECIAIBASAYDQIgAQ0CIAENBiACAQEMBAEBIAIBAiACAQEgGA0CIAENAiABDQIgAQ0DIAIBAQwEAQEgAgECIAIBASADAQMgAgEEIAEBBCAHDQIgAQ0CIAENAiACDQIgAgEBDAQBASACAQIgAgEBIAIBBSABAQQgAQEEIAcNAiABDQIgAQ0CIAMNASACAQEMBAEBIAIBAiACAQEgAgECIAEBAiABAQIgAwECIAkNAiABDQIgAQ0CIAYBAQwEAQEgAgECIAIBASACAQIgAQECIAEBBCABAQQgBw0FIAkBAQwEAQEgAgECIAIBASACAQIgAQECIAEBBCABAQQgBw0FIAcBAwwEAQEgAgECIAIBASACAQIgAQECIAEBAiADAQIgCg0CIAcBAg0DAQEMAwEBIAIBAiACAQEgAgECIAEBAiABAQIgAwECIBEBAg0FAQEMAwEBIAIBAiACAQEgAgEFIAEBAiADAQIgDwECDQgBAQwCAQEgAgECIAIBASADAQMgAgECIAMBAiANAQINCgEBDAIBASACAQIgAgEBIBoBAg0NAQEMAQEBIAIBAiACAQEgFwEDDQ8BAQwBAQEgAgECIAIBASAUAQMNEwECIAIBAiADASsgAwECIDEBAQABAQEgLwEBAAMBLwAC","%%IMG2ADMAHQAJAQIAMAEBIAIBAgAtAQIgBAECACsBAiAGAQIAKAEBDAEBASAIAQIAIgEFDAEBASADDQIgBQEeAAMBASADAQEMAgEBIAINBCAGAQMgGQEBAAEBASADAQEMAwEBIAINAiABDQIgAQ0BIAYBAyAXAQIgAwEBDAMBASACDQIgAQ0CIAENAiAIARQgAwECIAIBAQwEAQEgAg0CIAENAiABDQMgAQ0BIAYBFCACAQIgAgEBDAQBASACDQIgAQ0CIAENAyABDQIgFwECIAIBAiACAQEMBAEBIAINAiABDQIgAQ0CIAINAyAXAQEgAgECIAIBAQwEAQEgAg0CIAENAiABDQMgAQ0DIBcBASACAQIgAgEBDAQBASACDQIgAQ0CIAENAyABDQIgCwEDIAIBAiACAQIgAgEBIAIBAiACAQEMBAEBIAINBSABDQMgAQ0DIAkBBSABAQMgAQECIAIBASACAQIgAgEBDAQBASAEDQIgAg0CIAINAyAJAQIgAQECIAEBAyABAQIgAgEBIAIBAiACAQEMBAEBIAgNAiACDQIgCgECIAEBAiABAQYgAgEBIAIBAiACAQEMBAEDIAcNASACDQIgCgECIAEBAiABAQYgAgEBIAIBAiACAQEMAwEBDQMBAiAIDQIgCgECIAEBAiABAQIgAQEDIAIBASACAQIgAgEBDAMBAQ0FAQIgBw0BIAoBAiABAQIgAQECIAEBAyACAQEgAgECIAIBAQwCAQENCAECIBABBSABAQIgAgECIAIBASACAQIgAgEBDAIBAQ0KAQIgDwEDIAIBAiACAQIgAgEBIAIBAiACAQEMAQEBDQ0BAiAaAQEgAgECIAIBAQwBAQENDwEDIBcBASACAQIgAgECDRMBAyAUAQEgAgECIAMBKyADAQIgMQEBAAEBASAvAQEAAwEvAAI="]}}}}],"d":{"toggleButton":{"name":"toggleButton","size":[100,100],"resizable":1,"margin":[1,1,1,1],"description":"A graphical drop-in replacement for checkboxes.","script":"on view do\n i:extract arg where arg..type=\"image\" from ims.value\n c.show:card.show\n c.clear[]\n if 1~count i\n  f:first i\n  if b.value c.paste[f .5*c.size-f.size] end \n end\n if 2~count i\n  f:i[b.value]\n  c.paste[f .5*c.size-f.size]\n end\nend\n\non click do\n set_value[!get_value[]]\n card.event[\"click\"]\nend\n\non get_value do b.value end\non set_value x do b.value:x view[] end\non get_images do ims.value end\non set_images x do ims.value:x end","template":"on click do\n \nend","attributes":{"name":["value","images"],"label":["Value","Images"],"type":["bool","rich"]},"widgets":{"c":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"border":0,"scale":1},"b":{"type":"button","size":[100,100],"pos":[0,0],"script":"on click do\n \nend","show":"transparent","style":"invisible"},"ims":{"type":"field","size":[100,20],"pos":[121,5],"show":"none","border":1,"value":{"text":["","i"],"font":["",""],"arg":["","%%IMG2AA8ADwACAQsAAwEBIAsBAQABAQEgDQECIA0BAiANAQIgDQECIA0BAiANAQIgDQECIA0BAiANAQIgDQECIA0BAQABAQEgCwEBAAMBCwAC"]}}}}}}

Do you want the Juice? Do you need the Juice? Juice it or lose it with

The AnimButton Contraption

The animButton is another drop-in replacement for button widgets, this time for ordinary buttons. Just like a Button widget, this produces click[] events when clicked,  and respects .show for transparency. The first image is the default appearance of the button. When clicked, the button will cycle forward-and-back through the provided images. For example, if there are 3 images {0,1,2}, they will be displayed in the order {0,1,2,1,0}. If images are smaller than the bounding box of the contraption, they will be drawn centered.

%%WGT0{"w":[{"name":"animButton1","type":"contraption","size":[29,27],"pos":[249,73],"show":"transparent","def":"animButton","widgets":{"c":{"size":[29,27]},"b":{"size":[29,27]},"ims":{"size":[100,6],"pos":[50,1],"value":{"text":["","i","i","i","i"],"font":["","","","",""],"arg":["","%%IMG2ABkAGQABARcAAQEBIBcBAiAXAQIgFwECIBcBAiAXAQIgFwECIBcBAiAXAQIgFwECIBcBAiAXAQIgFwECIBcBAiAXAQIgFwECIBcBAiAXARsNFwECDRcBAg0XAQINFwECDRcBGg==","%%IMG2ABkAGQBMARcAAQEBDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXARsNFwECDRcBGg==","%%IMG2ABkAGQCWARoMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBGg==","%%IMG2ABkAGQCWAWYMFQEDDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBAgwXAQIMFwECDBcBGg=="]}},"ai":{"size":[100,5],"pos":[50,10],"value":"12"}}}],"d":{"animButton":{"name":"animButton","size":[100,100],"resizable":1,"margin":[1,1,1,1],"description":"A graphical drop-in replacement for buttons.","version":1,"script":"on rev x do x @ (-1+count x)-range count x end\n\non view do\n i:ims.images\n f:first i\n c.show:card.show\n c.clear[]\n if c.animated\n  s:(range count i),1 drop rev[range count i]\n  a:floor ai.text/2\n  f:f unless i[s[a]]\n  if a~(count s)-1 c.animated:b.locked:0 else ai.text:1+ai.text end\n end\n c.paste[f .5*c.size-f.size]\nend\n\non click do\n if !b.locked\n  ai.text:0\n  c.animated:b.locked:1\n  view[]\n  card.event[\"click\"]\n end\nend\n\non get_images do ims.value end\non set_images x do ims.value:x end","template":"on click do\n \nend","attributes":{"name":["images"],"label":["Images"],"type":["rich"]},"widgets":{"c":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"script":"on click pos do\nend","border":0,"scale":1},"b":{"type":"button","size":[100,100],"pos":[0,0],"show":"transparent","style":"invisible"},"ims":{"type":"field","size":[100,20],"pos":[121,5],"show":"none","border":1},"ai":{"type":"field","size":[100,20],"pos":[121,37],"show":"none","style":"plain"}}}}}
(+3)

these are so cool! I'm trying the animated buttons out and am curious about something: I have one button that goes to another card and another that displays a line from the dialogizer. the contraption works perfectly, but in these two cases, the animation either isn't seen (going to another card) or finishes after the event has completed (dialogizer). is it possible to have the button animation finish and then complete whatever event is being handled in the script?

Developer(+3)

Sure! You could modify the script of the AnimButton prototype to add another event. The existing script fragment that completes the animation looks something like:

if a~(count s)-1 c.animated:b.locked:0 else ai.text:1+ai.text end

Reformatted to be a bit clearer,

if a~(count s)-1
 c.animated:b.locked:0
else
 ai.text:1+ai.text
end

When "c" is set to no longer be "animated", we could inject a new event to the "card" (the outer scripts of the contraption instance):

if a~(count s)-1
 c.animated:b.locked:0
 card.event["finish"]
else
 ai.text:1+ai.text
end

It would also be a good idea to modify Prototype -> Properties... -> Template Script to include a handler for this new event:

on click do
end
on finish do
end
(+1)

this worked perfectly! thank you so much for your help :}

I'd love to spice up my life with the toggle button, but whenever I paste the script into a new contraption , it keeps telling me there are errors in the script. I have no idea how the script works, so I have no way to debug anything -- all I can do is report it...

(+1)

I think you're pasting it into the wrong place.

Code snippets that start with %%WGT are widgets and should be pasted directly onto a card. Not into a script container or a new prototype, just flat out paste it directly onto any normal card.

After it's in your deck it exists as an available contraption for your project. You can delete that pasted version of the contraption if you want and then make new copies of it from the widget menu (New Contraption...) later. 

And of course, you can also freely open it's prototype screen to edit it once it's there.

(Similarly a code snippet that starts with %%CRD is a whole card, and %%IMG is image data)

(+3)

Thanks for the quick reply! And also for the extra information. Everyone is very helpful, but there are also a lot of assumptions that I'm not aware of. I'm liking the program. but I have an art background so getting to grips with the technical aspects may take some time...

(+2)

I also came into decker from an art background and had to ask a lot of questions to get to up to speed with the technical stuff I wasn't familiar with, so I completely get it. Folks here are generally very happy to help, so please ask anytime you need a little help or clarification. :D

Developer (1 edit) (+3)

Do you pine for diet colas from the 1970s? Indulge yourself with

The TabBar Contraption:


Configure a set of newline-delimited options, and this contraption allows you to make an exclusive selection among them. In concert with showing/hiding other widgets or manipulating the data stored in other widgets, this can be used to create the appearance of "tabbed" UIs. This contraption supports the standard .show, .font, and .locked attributes. You can obtain the list of options with the .options attribute, and the selected tab (by name) with the .value attribute. When a tab is selected, this contraption provides a click[] event with no arguments.

%%WGT0{"w":[{"name":"tabbar","type":"contraption","size":[168,34],"pos":[184,140],"def":"tabbar","widgets":{"o":{"size":[100,7],"pos":[191,0]},"c":{"size":[168,34]},"i":{"size":[100,8],"pos":[191,11]}}}],"d":{"tabbar":{"name":"tabbar","size":[100,100],"resizable":1,"margin":[1,1,1,1],"description":"a tab bar, allowing the user to make an exclusive selection among several choices.","version":1.1,"script":"on get_options_text do o.text end\non set_options_text x do\n o.text:x\n i.interval:0,(count \"\\n\" split o.text)-1\n view[]\nend\non get_options do \"\\n\" split o.text end\non set_options x do set_options_text[\"\\n\" fuse x] x end\non get_value do get_options[][i.value] end\non set_value x do v:get_options[] i.value:sum (range count v)*v=x x view[] end\n\nbf:image[\"%%IMG2AAsABwADAQUABQEBIAUBAQADAQEgBwEBAAEBASAJAQIgCQECIAkBDA==\"] bb:image[\"%%IMG2AAsABwADAQUABQEBIAUBAQADAQEgAQEFIAEBAQABAQEgAQEHIAEBAiABAQcgAQECIAEBByABAQw=\"]\n\non view do\n c.show:card.show\n c.font:card.font\n c.clear[]\n v:get_options[]\n w:c.size[0]/count v\n each x ix in v\n  sel:ix~i.value\n  b:(ix*w),0,(w+ix<-1+count v),c.size[1]\n  c.segment[(bf,bb)[sel] b 5,4,5,2]\n  c.pattern:(1,32)[sel]\n  c.text[x b+(0,1,0,0) \"center\"]\n end\nend\n\non click pos do\n if !card.locked\n  v:get_options[]\n  w:c.size[0]/count v\n  p:get_value[]\n  set_value[v[floor(first pos)/w]]\n  if !p~get_value[] card.event.click end\n end\nend","template":"on click do\n \nend","attributes":{"name":["options_text"],"label":["Options"],"type":["code"]},"widgets":{"o":{"type":"field","size":[100,20],"pos":[123,1],"show":"none","style":"plain","value":"One\nTwo\nThree"},"c":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"border":0,"scale":1},"i":{"type":"slider","size":[100,25],"pos":[123,32],"show":"none","interval":[0,2]}}}}}
Developer(+3)

Another variation that might be useful for prototyping and documentation-

The scriptViewer Contraption:

A tabbed text field which allows the user to view (or edit!) the script of several widgets on the current card. The "Sources" should be a newline-delimited list of widget names. If "card" or "deck" are specified, the scriptViewer will access the script of the current card or the deck, respectively.

%%WGT0{"w":[{"name":"scriptViewer","type":"contraption","size":[189,106],"pos":[170,144],"def":"scriptViewer","widgets":{"o":{"size":[100,21],"pos":[212,1],"value":"deck\ncard"},"c":{"size":[189,18]},"i":{"size":[100,26],"pos":[212,34],"interval":[0,1]},"scr":{"size":[185,85]}}}],"d":{"scriptViewer":{"name":"scriptViewer","size":[100,100],"resizable":1,"margin":[3,20,3,3],"description":"a tabbed editor for viewing and editing the scripts of one or more widgets on the current card.","version":1,"script":"on get_options_text do o.text end\non set_options_text x do\n o.text:x\n i.interval:0,(count \"\\n\" split o.text)-1\n view[]\nend\non get_options do \"\\n\" split o.text end\non set_options x do set_options_text[\"\\n\" fuse x] x end\non get_value do get_options[][i.value] end\non set_value x do v:get_options[] i.value:sum (range count v)*v=x x view[] end\n\nbf:image[\"%%IMG2AAsABwADAQUABQEBIAUBAQADAQEgBwEBAAEBASAJAQIgCQECIAkBDA==\"] bb:image[\"%%IMG2AAsABwADAQUABQEBIAUBAQADAQEgAQEFIAEBAQABAQEgAQEHIAEBAiABAQcgAQECIAEBByABAQIgAQEHIAEBAQ==\"]\n\non target do\n val:get_value[]\n if val~\"deck\" deck elseif val~\"card\" deck.card else deck.card.widgets[val] end\nend\non change do\n target[].script:scr.text\nend\n\non view do\n c.font:card.font\n c.clear[]\n v:get_options[]\n w:(.7*c.size[0])/count v\n each x ix in v\n  sel:ix~i.value\n  b:(ix*w),0,(w+ix<-1+count v),c.size[1]\n  c.segment[(bf,bb)[sel] b 5,4,5,2]\n  c.pattern:(1,32)[sel]\n  c.text[x b+(0,1,0,0) \"center\"]\n end\n scr.text:target[].script\n scr.locked:card.locked\nend\n\non click pos do\n v:get_options[]\n w:(.7*c.size[0])/count v\n set_value[v[floor(first pos)/w]]\nend","image":"%%IMG2AGQAZAD/AP8A/wD/AP8A/wCqAWUgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAQIgYgECIGIBAiBiAWU=","attributes":{"name":["options_text"],"label":["Sources"],"type":["code"]},"widgets":{"o":{"type":"field","size":[100,20],"pos":[123,1],"show":"none","style":"plain","value":"card"},"c":{"type":"canvas","size":[100,18],"pos":[0,0],"locked":1,"volatile":1,"show":"transparent","border":0,"pattern":32,"scale":1},"i":{"type":"slider","size":[100,25],"pos":[123,32],"show":"none","interval":[0,2]},"scr":{"type":"field","size":[96,79],"pos":[2,19],"volatile":1,"border":0,"scrollbar":1,"style":"code"}}}}}
Developer(+1)

Do you like car analogies for your UI components? Indulge yourself with

The RadioButton Contraption:


RadioButtons behave like checkboxes, but only one of the RadioButtons on a card with the same .group property may have a truthy .value. This contraption respects the standard .font, .show, and .locked attributes and fires a click[] event when clicked.

%%WGT0{"w":[{"name":"radio","type":"contraption","size":[134,18],"pos":[58,82],"font":"menu","show":"transparent","def":"radioButton","widgets":{"c":{"show":"transparent"},"l":{"font":"menu","show":"transparent","value":"First"},"b":{},"g":{"value":"a"}}}],"d":{"radioButton":{"name":"radioButton","size":[134,18],"resizable":1,"margin":[20,1,4,1],"description":"a selectable button which permits only a single selection within a group.","version":1,"script":"on get_label do l.text end\non set_label x do l.text:x view[] end\non get_group do g.text end\non set_group x do g.text:x end\non get_value do b.value end\non set_value_raw x do b.value:x view[] end\ndot:image[\"%%IMG0ABAADgAAAAAAAAAAB4APwA/AD8APwAeAAAAAAAAAAAA=\"]\noutline:image[\"%%IMG2ABAADgAVAQQACgECIAQBAgAHAQEgCAEBAAYBASAIAQEABQEBIAoBAQAEAQEgCgEBAAQBASAKAQEABAEBIAoBAQAFAQEgCAEBAAYBASAIAQEABwECIAQBAgAKAQQAFw==\"]\non view do\n l.font:       card.font\n l.show:c.show:card.show\n b.locked:card.locked\n if card.locked (outline,dot)..map[1 dict 13] end # gray out\n c.clear[]\n c.paste[outline]\n if b.value c.paste[dot 0,0 1] end\nend\non set_value x do\n gr:extract value where value..group=g.text from card.parent.widgets\n if x gr.  .value_raw:0\n else gr[0].value_raw:1\n end\n set_value_raw[x]\nend\non click do\n if !card.locked\n  set_value[1]\n  card.event.click\n end\nend","template":"on click do\n \nend","attributes":{"name":["label","group"],"label":["Label","Group"],"type":["string","string"]},"widgets":{"c":{"type":"canvas","size":[16,14],"pos":[1,2],"locked":1,"volatile":1,"border":0,"scale":1},"l":{"type":"field","size":[114,16],"pos":[19,1],"locked":1,"border":0,"style":"plain"},"b":{"type":"button","size":[134,18],"pos":[0,0],"style":"invisible"},"g":{"type":"field","size":[100,20],"pos":[149,-60],"locked":1,"show":"none"}}}}}
(1 edit) (+6)

This has been useful for me so I might as well put it here.

Palette Adjuster

A sort of supplement to Palette Import. If you only want to adjust certain colors this thing will let you change them one-by-one by entering individual hexcodes. The color boxes are previews of what you'll be replacing.

Be a little careful if you want to reverse or otherwise dramatically change the 1-bit color slots. This does not have the color sorting feature that PalImport does. Decker's user interface will be very difficult to navigate if you set both of the 1-bit colors to the same hexcode. :)

%%WGT0{"w":[{"name":"PaletteAdjuster","type":"contraption","size":[316,211],"pos":[98,66],"def":"PaletteAdjuster","widgets":{"field1":{},"button99":{},"button0":{},"whitehex":{},"blackhex":{},"yellowhex":{},"button1":{},"button2":{},"button3":{},"orangehex":{},"redhex":{},"magentahex":{},"button4":{},"button5":{},"purplehex":{},"bluehex":{},"button6":{},"button7":{},"button8":{},"cyanhex":{},"greenhex":{},"darkgreenhex":{},"button9":{},"button17":{},"button18":{},"brownhex":{},"tanhex":{},"lightgrayhex":{},"button19":{},"button20":{},"mediumgrayhex":{},"darkgrayhex":{},"button21":{},"orangepreview":{},"blackpreview":{},"whitepreview":{},"yellowpreview":{},"redpreview":{},"magentapreview":{},"purplepreview":{},"bluepreview":{},"cyanpreview":{},"greenpreview":{},"darkgreenpreview":{},"brownpreview":{},"tanpreview":{},"lightgraypreview":{},"mediumgraypreview":{},"darkgray":{}}}],"d":{"PaletteAdjuster":{"name":"PaletteAdjuster","size":[316,211],"margin":[0,0,0,0],"description":"Modify each color of your palette individually.","version":1,"image":"%%IMG2ATwA0wH/Af8BfACcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFABIBSQBBAQMAmAEFABIBSQBBAQMAmAEFABIBAgBFAQIAQQEDAJgBBQASAQIARQECAEEBAwCYAQUAEgECAEUBAgBBAQMAmAEFABIBAgBFAQIAQQEDAJgBBQASAQIARQECAEEBAwCYAQUAEgECAEUBAgBBAQMAmAEFABIBAgBFAQIAQQEDAJgBBQASAQIARQECAEEBAwCYAQUAEgECAEUBAgBBAQMAmAEFABIBAgBFAQIAQQEDAJgBBQASAQIARQECAEEBAwCYAQUAEgECAEUBAgBBAQMAmAEFABIBAgBFAQIAQQEDAJgBBQAGAZIABAEDAJgBBQAGAZIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBAhSOAQIABAEDAJgBBQAGAQIUjgECAAQBAwCYAQUABgECFI4BAgAEAQMAmAEFAAYBkgAEAQMAmAEFAAYBkgAEAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAQUAnAEDAJgBBQCcAQMAmAEFAJwBAwCYAf8B/wH/Abo=","attributes":{"name":[],"label":[],"type":[]},"widgets":{"field1":{"type":"field","size":[74,12],"pos":[21,8],"locked":1,"show":"transparent","border":0,"value":"1-Bit  Patterns"},"button99":{"type":"button","size":[40,18],"pos":[60,25],"script":"on click do\n  patterns[colors.white]:\"%h\" parse whitehex.text\nend","text":"Apply"},"button0":{"type":"button","size":[40,18],"pos":[60,47],"script":"on click do\n  patterns[colors.black]:\"%h\" parse blackhex.text\nend","text":"Apply"},"whitehex":{"type":"field","size":[44,18],"pos":[12,25],"style":"code","align":"center"},"blackhex":{"type":"field","size":[44,18],"pos":[12,47],"align":"center"},"yellowhex":{"type":"field","size":[44,18],"pos":[12,73],"style":"code","align":"center"},"button1":{"type":"button","size":[40,18],"pos":[60,73],"script":"on click do\n  patterns[colors.yellow]:\"%h\" parse yellowhex.text\nend","text":"Apply"},"button2":{"type":"button","size":[40,18],"pos":[60,95],"script":"on click do\n  patterns[colors.orange]:\"%h\" parse orangehex.text\nend","text":"Apply"},"button3":{"type":"button","size":[40,18],"pos":[60,117],"script":"on click do\n  patterns[colors.red]:\"%h\" parse redhex.text\nend","text":"Apply"},"orangehex":{"type":"field","size":[44,18],"pos":[12,95],"style":"code","align":"center"},"redhex":{"type":"field","size":[44,18],"pos":[12,117],"align":"center"},"magentahex":{"type":"field","size":[44,18],"pos":[12,139],"style":"code","align":"center"},"button4":{"type":"button","size":[40,18],"pos":[60,139],"script":"on click do\n  patterns[colors.magenta]:\"%h\" parse magentahex.text\nend","text":"Apply"},"button5":{"type":"button","size":[40,18],"pos":[60,161],"script":"on click do\n  patterns[colors.purple]:\"%h\" parse purplehex.text\nend","text":"Apply"},"purplehex":{"type":"field","size":[44,18],"pos":[12,161],"align":"center"},"bluehex":{"type":"field","size":[44,18],"pos":[12,183],"style":"code","align":"center"},"button6":{"type":"button","size":[40,18],"pos":[60,183],"script":"on click do\n  patterns[colors.blue]:\"%h\" parse bluehex.text\nend","text":"Apply"},"button7":{"type":"button","size":[40,18],"pos":[215,29],"script":"on click do\n  patterns[colors.cyan]:\"%h\" parse cyanhex.text\nend","text":"Apply"},"button8":{"type":"button","size":[40,18],"pos":[215,51],"script":"on click do\n  patterns[colors.green]:\"%h\" parse greenhex.text\nend","text":"Apply"},"cyanhex":{"type":"field","size":[44,18],"pos":[167,29],"style":"code","align":"center"},"greenhex":{"type":"field","size":[44,18],"pos":[167,51],"align":"center"},"darkgreenhex":{"type":"field","size":[44,18],"pos":[167,73],"script":"on change val do\n \nend","style":"code","align":"center"},"button9":{"type":"button","size":[40,18],"pos":[215,73],"script":"on click do\n  patterns[colors.darkgreen]:\"%h\" parse darkgreenhex.text\nend","text":"Apply"},"button17":{"type":"button","size":[40,18],"pos":[215,95],"script":"on click do\n  patterns[colors.brown]:\"%h\" parse brownhex.text\nend","text":"Apply"},"button18":{"type":"button","size":[40,18],"pos":[215,117],"script":"on click do\n  patterns[colors.tan]:\"%h\" parse tanhex.text\nend","text":"Apply"},"brownhex":{"type":"field","size":[44,18],"pos":[167,95],"style":"code","align":"center"},"tanhex":{"type":"field","size":[44,18],"pos":[167,117],"align":"center"},"lightgrayhex":{"type":"field","size":[44,18],"pos":[167,139],"script":"on change val do\n \nend","style":"code","align":"center"},"button19":{"type":"button","size":[40,18],"pos":[215,139],"script":"on click do\n  patterns[colors.lightgray]:\"%h\" parse lightgrayhex.text\nend","text":"Apply"},"button20":{"type":"button","size":[40,18],"pos":[215,161],"script":"on click do\n  patterns[colors.mediumgray]:\"%h\" parse mediumgrayhex.text\nend","text":"Apply"},"mediumgrayhex":{"type":"field","size":[44,18],"pos":[167,161],"align":"center"},"darkgrayhex":{"type":"field","size":[44,18],"pos":[167,183],"style":"code","align":"center"},"button21":{"type":"button","size":[40,18],"pos":[215,183],"script":"on click do\n  patterns[colors.darkgray]:\"%h\" parse darkgrayhex.text\nend","text":"Apply"},"orangepreview":{"type":"canvas","size":[46,18],"pos":[104,95],"locked":1,"image":"%%IMG2AC4AEiL/Iv8i/yI/","scale":1},"blackpreview":{"type":"canvas","size":[46,18],"pos":[104,47],"locked":1,"image":"%%IMG2AC4AEgH/Af8B/wE/","scale":1},"whitepreview":{"type":"canvas","size":[46,18],"pos":[104,25],"locked":1,"image":"%%IMG2AC4AEiD/IP8g/yA/","scale":1},"yellowpreview":{"type":"canvas","size":[46,18],"pos":[104,73],"locked":1,"image":"%%IMG2AC4AEiH/If8h/yE/","scale":1},"redpreview":{"type":"canvas","size":[46,18],"pos":[104,117],"locked":1,"image":"%%IMG2AC4AEiP/I/8j/yM/","scale":1},"magentapreview":{"type":"canvas","size":[46,18],"pos":[104,139],"locked":1,"image":"%%IMG2AC4AEiT/JP8k/yQ/","scale":1},"purplepreview":{"type":"canvas","size":[46,18],"pos":[104,161],"locked":1,"image":"%%IMG2AC4AEiX/Jf8l/yU/","scale":1},"bluepreview":{"type":"canvas","size":[46,18],"pos":[104,183],"locked":1,"image":"%%IMG2AC4AEib/Jv8m/yY/","scale":1},"cyanpreview":{"type":"canvas","size":[46,18],"pos":[259,27],"locked":1,"image":"%%IMG2AC4AEif/J/8n/yc/","scale":1},"greenpreview":{"type":"canvas","size":[46,18],"pos":[259,49],"locked":1,"image":"%%IMG2AC4AEij/KP8o/yg/","scale":1},"darkgreenpreview":{"type":"canvas","size":[46,18],"pos":[259,71],"locked":1,"image":"%%IMG2AC4AEin/Kf8p/yk/","scale":1},"brownpreview":{"type":"canvas","size":[46,18],"pos":[259,93],"locked":1,"image":"%%IMG2AC4AEir/Kv8q/yo/","scale":1},"tanpreview":{"type":"canvas","size":[46,18],"pos":[259,115],"locked":1,"image":"%%IMG2AC4AEiv/K/8r/ys/","scale":1},"lightgraypreview":{"type":"canvas","size":[46,18],"pos":[259,137],"locked":1,"image":"%%IMG2AC4AEiz/LP8s/yw/","scale":1},"mediumgraypreview":{"type":"canvas","size":[46,18],"pos":[259,161],"locked":1,"image":"%%IMG2AC4AEi3/Lf8t/y0/","scale":1},"darkgray":{"type":"canvas","size":[46,18],"pos":[259,183],"locked":1,"image":"%%IMG2AC4AEi7/Lv8u/y4/","scale":1}}}}}
(3 edits) (+5)

Ever wanted to be able to have text fields that are colours other than black or white, or indeed have white text on a transparent background?

ColourText can do that!


It's a pretty simple contraption, there's a field for rich text and a field for the desired colour (by decker palette index). It'll flow/wrap the text fine, but if you're resizing in widgets mode it won't update until you switch back to interact mode. It can't do the "editing in interact mode" thing like real text fields can nor does it have support for adding borders or being able to scroll. If you need those I'll say it's a challenge for the reader at the moment.

Give it a try though! Let me know if there's any obvious bugs or fixes I ought to do.

Edit: you may want to grab the updated version from the comments - it sets the internal canvas as "volatile" so that when you save your deck it doesn't include the image of text, thus saving on space. But it has the drawback of playing a bit funny with transition effects in a way that is workaround-able but requires some coding, so I'm leaving the original version here in case that's easier for you

%%WGT0{"w":[{"name":"colourtext1","type":"contraption","size":[134,65],"pos":[142,122],"show":"transparent","def":"colourtext","widgets":{"canvas1":{"size":[134,65],"image":"%%IMG2AIYAQQD/AJUjAQAOIwEADCMBAAkjAgABIwIABCMBAAIjAQAFIwEACSMBAA4jAQAIIwEAAiMBACgjAQAOIwEADCMBAAojAQACIwEABCMBAAIjAQAPIwEADiMBAAsjAQAoIwEABSMCAAMjAgACIwEAAiMBAAQjAgACIwMABCMCAAMjAQACIwEAAyMDAAEjAwACIwIAAiMDAAMjAwACIwIAAiMBAAMjAQABIwMABiMCAAEjAwAEIwIAAyMCAAIjAwABIwIAAyMCAAMjAwAJIwEABCMBAAIjAQABIwEAAiMBAAEjAQABIwEAByMBAAIjAQAHIwEAAiMBAAIjAQAEIwEAAiMBAAIjAQACIwEAASMBAAcjAQACIwEAAiMBAAIjAQABIwEAAyMBAAgjAQACIwEABCMBAAIjAQABIwEAAiMBAAEjAQACIwEAAiMBAAEjAQACIwEAASMBAAwjAQAEIwEAAiMBAAEjAQACIwEAASMCAAYjAwACIwEABSMDAAIjAQACIwEABCMBAAIjAQACIwEAAiMBAAIjAgAFIwEAAiMEAAMjAQAEIwEACCMBAAIjAQAEIwEABCMBAAIjAQABIwEAAiMBAAIjAQABIwQAAiMCAAojAQAEIwEAAiMBAAEjAQACIwEAASMBAAEjAQAEIwEAAiMBAAIjAQAEIwEAAiMBAAIjAQACIwEABCMBAAIjAQACIwEAAiMBAAQjAQAEIwEAAiMBAAUjAQABIwEAAyMBAAgjAQACIwEABCMBAAIjAQABIwEAAiMBAAEjAQACIwEAAiMBAAEjAQAHIwEACSMEAAIjAgADIwIAAiMBAAIjAQAEIwMAAyMBAAQjAwACIwEAAiMBAAUjAQABIwEAAiMBAAIjAQABIwMABiMBAAIjAgACIwEAAyMBAAMjAQACIwEABCMBAAMjAQAEIwIAAyMCAAIjAQACIwEAAiMBAAIjAgACIwMAXyMBAIQjAQDFIwIAASMCAAMjAwADIwMAHSMCAAcjAwAQIwIALSMBAAwjAgAFIwIABCMCAB8jAgAGIwIAEiMCABcjAQAfIwUAASMCAAEjBAACIwQAAyMEAAIjAgABIwIAAiMEAAIjBQACIwQABCMEAAMjBAACIwUAAiMEAAIjAwARIwEAFCMCAAEjAwAEIwIAAiMCAAEjAgACIwIABCMCAAMjAgACIwIAASMDAAMjAgACIwIAASMCAAIjAgACIwIABiMCAAMjAgACIwIAASMCAAIjAgACIwIAAiMCAAIjAQAEIwIAAiMDAAMjAwAVIwEAASMBAAIjAQADIwIAAiMCAAEjAgACIwIABCMCAAMjAgACIwIAASMCAAQjAgACIwIAASMCAAIjAgACIwIABiMCAAMjAgACIwIAASMCAAIjAgACIwIAAiMDAAgjAQABIwEAAiMBAAEjAQACIwEAFSMBAAEjAQACIwEAAyMCAAIjAgABIwIAAiMCAAQjAgADIwYAASMCAAQjBgABIwIAAiMCAAIjAgAGIwIAAyMCAAIjAgABIwIAAiMCAAIjAgADIwMABSMDAAEjAQACIwEAASMBAAIjAQAVIwEAASMBAAIjAQADIwIAAiMCAAEjAgACIwIABCMCAAMjAgAFIwIABCMCAAUjAgACIwIAAiMCAAYjAgADIwIAAiMCAAEjAgACIwIAAiMCAAQjAwADIwEAAiMBAAEjAQACIwEAASMBAAIjAQAVIwEAASMBAAIjAQADIwIAAiMCAAEjAgACIwIABCMCAAMjAgADIwEAASMCAAQjAgADIwEAASMCAAIjAgACIwIABiMCAAMjAgACIwIAASMCAAIjAgACIwIAAiMBAAIjAgAEIwMAASMBAAIjAQACIwMAHyMFAAEjAgACIwIABCMCAAQjBAACIwIABSMEAAIjAgACIwIAAyMCAAUjAgAEIwQAAiMCAAIjAgADIwIAAiMDAP8A/wBBIwEAAiMBAAIjAQAVIwEAECMBAAQjAQAwIwEAJSMBAAIjAQAVIwEAECMBAAQjAQAwIwEAISMCAAEjAwAEIwMAAyMBAAEjAgACIwIAAyMDAAQjAgACIwMAAyMDAAMjAwABIwEAASMCAAIjAgACIwMAAyMDAAEjAwADIwIAAiMBAAEjAgACIwIAAiMDAAIjAwAhIwEAAiMBAAQjAQAGIwIAAyMBAAIjAQABIwEAAiMBAAYjAQABIwEAAiMBAAEjAQACIwEABCMBAAIjAgAGIwEAASMBAAIjAQABIwEABCMBAAIjAQAEIwEAASMCAAMjAQACIwEAASMBAAIjAQACIwEAIiMBAAIjAQAFIwIABCMBAAQjBAABIwEAAiMBAAQjAwABIwEAAiMBAAEjAQACIwEABCMBAAIjAQAFIwMAASMBAAIjAQACIwIAAiMBAAIjAQACIwMAASMBAAQjBAABIwEAAiMBAAIjAQAiIwEAAiMBAAcjAQADIwEABCMBAAQjAQACIwEAAyMBAAIjAQABIwEAAiMBAAEjAQACIwEABCMBAAIjAQAEIwEAAiMBAAEjAQACIwEABCMBAAEjAQACIwEAASMBAAIjAQABIwEABCMBAAQjAQACIwEAAiMBACIjAQADIwEAAyMDAAQjAQAFIwIAAyMDAAQjAwABIwEAAiMBAAIjAwAFIwEAASMBAAUjAwABIwEAAiMBAAEjAwACIwMAAyMDAAEjAQAFIwIAAiMBAAIjAQADIwEAaiMBAIUjAQD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD8","pattern":35},"field1":{"pos":[-186,154],"value":{"text":["Look at all this text, it comes in ","different fonts"," and it's red and transparent"],"font":["","menu",""],"arg":["","",""]}}}}],"d":{"colourtext":{"name":"colourtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Like a text box, but with colour!","version":1,"script":"on get_colour do\n canvas1.pattern\nend\n\non set_colour x do\n canvas1.pattern:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non redraw do\n canvas1.clear[]\n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.text[field1.value 2,2,size]\nend\n\non view do\n redraw[]\nend","attributes":{"name":["value","colour"],"label":["Text","Colour (palette index)"],"type":["rich","number"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189]}}}}}
(+2)

Ooh this will come in handy!! :D

Developer(+2)

One possible refinement to this which would produce smaller deck sizes would be to mark the internal canvas as "volatile"; instead of saving the rendered bitmap of text, Decker would then regenerate the image at load time or the first view[] event. (This would also require you to save the pattern selection in a separate internal field.)

(+2)

Thanks, I have yet to get my head around "volatile" but I will experiment. I was hesitant to try because I wasn't sure whether it would play nice with transition functions, e.g. would it only call the "view" at the end of the transition?

I will experiment and see if I can get it working, since not having images saved in the deck files is probably nicer

(1 edit) (+2)

So I whipped up a version that uses volatiles, but it does indeed have the problem of, if you're transitioning between cards on a freshly opened deck, it doesn't draw the text in until the end of the transition, so it kind of "pops in". I've uploaded a quick example to show what I mean https://zine.milliesquilly.com/surprises/colourtextpopindemo.html

If there's something I'm missing here please let me know

Here's the new version of the contraption - I'm hestitant to replace the original since it's not a strict improvement, but if you're not using transitions or if you don't mind manually calling "view" on the contraption before the transition it does save on deck size

Edit: slightly updated version, did some experimenting and wasn't able to get manually calling "view" to work so I've exposed the redraw[] function itself. So if you want to use this version and need to refresh the contents before a transition (or whatever other fun things you're doing) you can call redraw[] on the widget to refresh it before your transition.

%%WGT0{"w":[{"name":"colourtext1","type":"contraption","size":[134,65],"pos":[145,125],"show":"transparent","def":"colourtext","widgets":{"canvas1":{"size":[134,65],"pattern":35},"field1":{"pos":[-186,154],"value":{"text":["Look at all this text, it comes in ","different fonts"," and it's red and transparent"],"font":["","menu",""],"arg":["","",""]}},"slider1":{"size":[116,25],"pos":[-52,149],"value":35}}}],"d":{"colourtext":{"name":"colourtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Like a text box, but with colour! With volatiles now. Exposes a redraw[] function if you need to refresh it manually for whatever reason.","version":1.2,"script":"on get_colour do\n slider1.value\nend\n\non set_colour x do\n slider1.value:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non redraw do\n canvas1.clear[]\n canvas1.pattern:slider1.value\n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.text[field1.value 2,2,size]\nend\n\non view do\n redraw[]\nend\n\non get_redraw do\n redraw\nend","attributes":{"name":["value","colour"],"label":["Text","Colour (palette index)"],"type":["rich","number"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189]},"slider1":{"type":"slider","size":[100,25],"pos":[-52,184],"interval":[0,47],"value":1,"style":"compact"}}}}}
(1 edit) (+1)

I have come up with a... sort of solution for drawing all the colour text at deck launch so that I don't have the "pop in after transition" issue

Essentially I've just put this function in my deck-level scripts to just cycle through all the cards and make them all draw on launch. Then I just call it from the "on view" of my starting card.

(removed, see below for better version)

This is kinda hacky (I didn't see an obvious way to check that the contraptions belong to the right prototype so I'm running it on any contraption) so if you have other contraptions with a redraw[] method that does something else this may not be good but it is working for my purposes!

(Apologies if there IS an obvious way to check which prototype a contraption belongs to and I'm just too eepy to figure it out right now)


Edit: better version, thanks IJ for the tip on picking the prototype name

on refreshcolourtext do
 each c in deck.cards
  each w in c.widgets
   if w.def.name="colourtext"
    w.redraw[]
   end
  end
 end
end
Developer(+2)

If you have a contraption x, you can obtain the contraption's prototype as "x.def" and the name of the contraption's prototype as "x.def.name"

(+2)

Thank you! I have improved it!

(+2)

Wow, thank you! Text color support in rich text has been something I was wishing for for a while.

(+2)

Hopefully the limitations aren't too much of an issue for you!

(1 edit) (+3)

I made a variant that lets you have text with a drop shadow, like in the following screenshot

Here's the copypaste dealio

%%WGT0{"w":[{"name":"shadowtext1","type":"contraption","size":[89,26],"pos":[350,98],"show":"transparent","def":"shadowtext","widgets":{"canvas1":{"size":[89,26],"pattern":37},"field1":{"pos":[-186,115],"value":{"text":["","Here's a test"],"font":["","menu"],"arg":["",""]}},"slider1":{"size":[95,25],"pos":[-52,110],"value":37},"slider2":{"size":[96,25],"pos":[58,110],"value":36}}}],"d":{"shadowtext":{"name":"shadowtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Colour text, with a drop shadow! Exposes a redraw[] function if you need to refresh it manually for whatever reason.","version":1,"script":"on get_colour do\n slider1.value\nend\n\non set_colour x do\n slider1.value:x\n redraw[]\nend\n\non get_shadow do\n slider2.value\nend\n\non set_shadow x do\n slider2.value:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non redraw do\n canvas1.clear[]\n \n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.pattern:slider2.value\n canvas1.text[field1.value 3,3,size]\n canvas1.pattern:slider1.value\n canvas1.text[field1.value 2,2,size]\nend\n\non view do\n redraw[]\nend\n\non get_redraw do\n redraw\nend","attributes":{"name":["value","colour","shadow"],"label":["Text","Colour (palette index)","Shadow (palette index)"],"type":["rich","number","number"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189]},"slider1":{"type":"slider","size":[100,25],"pos":[-52,184],"interval":[0,47],"value":1,"style":"compact"},"slider2":{"type":"slider","size":[100,25],"pos":[65,184],"interval":[0,47],"value":1,"style":"compact"}}}}}

And a slightly modified version of the refresh code to pick these up too

on refreshcolourtext do
 each c in deck.cards
  each w in c.widgets
   if (w.def.name="colourtext") | (w.def.name="shadowtext")
    w.redraw[]
   end
  end
 end
end

Good day, how can I resize the font for the drop shadow?

(1 edit) (+2)

The field where you enter the text is a rich text field so you can use Decker's font controls to pick a larger or smaller font. The drop shadow is just a duplicate of the main text offset one pixel down and right, so it should match the font etc of the text.

Hope this makes sense.

(+1)

I'll try to make sense of it, thank you very much for this one.

If you're still having trouble please reach out again and we'll figure it out!

(+1)

I came here looking for exactly this sort of thing after I'd already started writing my own contraption, and realized "wait I should check first". Well done.

I attempted to modify it further to add anchor support but after failing and then checking the docks, am I correct in gleaning that this isn't possible if the contraption uses rtext? 'Twould be nice to have centered text at least.

Developer(+1)

I don't see why this couldn't work for rtext. canvas.textsize[] and canvas.text[] both accept rtext and the latter accepts an anchor, provided the second argument supplies a bounding rectangle.

(1 edit)

Hmm. I had experimented with adding anchor to the canvas.text calls but it didn't seem to have any effect, so I took this quote as explanation as to why. But it occurred to me now that it's still wrapping the rtext left-wise so maybe I've misunderstood what anchors do here.

If x is an rtext table and pos is not a rectangle, the anchor a is ignored, text is drawn top-left aligned, and lines are not automatically wrapped.

Here's the modified version I made.

EDIT: got it working. Fixed version below. 

Developer

You appear to be using "anchor.value" when you mean "anchorType.text".

(1 edit) (+1)

Oh bugger, so I am. Type left over from an earlier version. Fixed that and now it works. Jolly good.

Here's the shadowtext version with anchor support:

%%WGT0{"w":[{"name":"title","type":"contraption","size":[461,33],"pos":[12,29],"show":"transparent","def":"shadowtext","widgets":{"canvas1":{"size":[461,33],"pattern":34},"field1":{"pos":[-186,122],"value":{"text":["","Title"],"font":["","deckbuilder"],"arg":["",""]}},"slider1":{"size":[273,25],"pos":[-52,117],"value":34},"slider2":{"size":[226,25],"pos":[300,117],"value":46},"anchorType":{"pos":[545,117],"value":"center"}}}],"d":{"shadowtext":{"name":"shadowtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Colour text, with a drop shadow! Exposes a redraw[] function if you need to refresh it manually for whatever reason.","version":2,"script":"on get_colour do\n slider1.value\nend\n\non set_colour x do\n slider1.value:x\n redraw[]\nend\n\non get_shadow do\n slider2.value\nend\n\non set_shadow x do\n slider2.value:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non get_anchor do\n anchorType.text\nend\n\non set_anchor x do\n anchorType.text:x\n redraw[]\nend\n\non redraw do\n canvas1.clear[]\n \n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.pattern:slider2.value\n canvas1.text[field1.value 3,3,size anchorType.text]\n canvas1.pattern:slider1.value\n canvas1.text[field1.value 2,2,size anchorType.text]\nend\n\non view do\n redraw[]\nend\n\non get_redraw do\n redraw\nend","attributes":{"name":["value","colour","shadow","anchor"],"label":["Text","Colour (palette index)","Shadow (palette index)","Anchor"],"type":["rich","number","number","string"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"script":"on click pos do\n \nend\n\non drag pos do\n \nend\n\non release pos do\n \nend","show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189]},"slider1":{"type":"slider","size":[100,25],"pos":[-52,184],"interval":[0,47],"value":1,"style":"compact"},"slider2":{"type":"slider","size":[100,25],"pos":[65,184],"interval":[0,47],"value":1,"style":"compact"},"anchorType":{"type":"field","size":[100,20],"pos":[184,184]}}}}}

And the normal text version with anchor:

%%WGT0{"w":[{"name":"colourtext1","type":"contraption","size":[100,62],"pos":[104,163],"show":"transparent","def":"colourtext","widgets":{"canvas1":{"size":[100,62],"pattern":34},"field1":{"pos":[-186,151],"value":{"text":["","I seem to be in a spot of bother."],"font":["","ahmArrow"],"arg":["",""]}},"slider1":{"pos":[-52,146],"value":34},"a":{"pos":[73,151],"value":"center"}}}],"d":{"colourtext":{"name":"colourtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Like a text box, but with colour! With volatiles now. Exposes a redraw[] function if you need to refresh it manually for whatever reason.","version":1.2,"script":"on get_colour do\n slider1.value\nend\n\non set_colour x do\n slider1.value:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non get_anchor do a.text end\non set_anchor x do a.text:x end\n\non redraw do\n canvas1.clear[]\n canvas1.pattern:slider1.value\n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.text[field1.value 2,2,size a.text]\nend\n\non view do\n redraw[]\nend\n\non get_redraw do\n redraw\nend","attributes":{"name":["value","colour","anchor"],"label":["Text","Colour (palette index)","Anchor"],"type":["rich","number","string"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189]},"slider1":{"type":"slider","size":[100,25],"pos":[-52,184],"interval":[0,47],"value":1,"style":"compact"},"a":{"type":"field","size":[100,20],"pos":[73,189],"style":"plain"}}}}}
(+2)

Hey, I realised while playing around with these for my next zine that since I'd left the hidden widgets that store the colour unlocked, it's possibly to inadvertently click them and change the colour. I've made updated versions of both contraptions that fix this (sorry I haven't included the anchor changes - but if you want to fix this in your own version you literally just need to open the contraption and lock the widgets)

Colour text:

%%WGT0{"w":[{"name":"colourtext1","type":"contraption","size":[100,100],"pos":[242,180],"show":"transparent","def":"colourtext","widgets":{"canvas1":{"pattern":35},"field1":{"value":"colour text"},"slider1":{"value":35}}}],"d":{"colourtext":{"name":"colourtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Like a text box, but with colour! With volatiles now. Exposes a redraw[] function if you need to refresh it manually for whatever reason.","version":1.3,"script":"on get_colour do\n slider1.value\nend\n\non set_colour x do\n slider1.value:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non redraw do\n canvas1.clear[]\n canvas1.pattern:slider1.value\n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.text[field1.value 2,2,size]\nend\n\non view do\n redraw[]\nend\n\non get_redraw do\n redraw\nend","attributes":{"name":["value","colour"],"label":["Text","Colour (palette index)"],"type":["rich","number"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189],"locked":1},"slider1":{"type":"slider","size":[100,25],"pos":[-52,184],"locked":1,"interval":[0,47],"value":1,"style":"compact"}}}}}

Shadow text

%%WGT0{"w":[{"name":"shadowtext1","type":"contraption","size":[100,100],"pos":[240,181],"show":"transparent","def":"shadowtext","widgets":{"canvas1":{"pattern":35},"field1":{"value":"Shadow text"},"slider1":{"value":35},"slider2":{"value":36}}}],"d":{"shadowtext":{"name":"shadowtext","size":[100,100],"resizable":1,"margin":[0,0,0,0],"description":"Colour text, with a drop shadow! Exposes a redraw[] function if you need to refresh it manually for whatever reason.","version":1.1,"script":"on get_colour do\n slider1.value\nend\n\non set_colour x do\n slider1.value:x\n redraw[]\nend\n\non get_shadow do\n slider2.value\nend\n\non set_shadow x do\n slider2.value:x\n redraw[]\nend\n\non get_value do\n field1.value\nend\n\non set_value x do\n field1.value:x\n redraw[]\nend\n\non redraw do\n canvas1.clear[]\n \n size:canvas1.textsize[field1.value canvas1.size[0]-4]\n canvas1.pattern:slider2.value\n canvas1.text[field1.value 3,3,size]\n canvas1.pattern:slider1.value\n canvas1.text[field1.value 2,2,size]\nend\n\non view do\n redraw[]\nend\n\non get_redraw do\n redraw\nend","attributes":{"name":["value","colour","shadow"],"label":["Text","Colour (palette index)","Shadow (palette index)"],"type":["rich","number","number"]},"widgets":{"canvas1":{"type":"canvas","size":[100,100],"pos":[0,0],"locked":1,"volatile":1,"show":"transparent","border":0,"scale":1},"field1":{"type":"field","size":[100,20],"pos":[-186,189],"locked":1},"slider1":{"type":"slider","size":[100,25],"pos":[-52,184],"locked":1,"interval":[0,47],"value":1,"style":"compact"},"slider2":{"type":"slider","size":[100,25],"pos":[65,184],"locked":1,"interval":[0,47],"value":1,"style":"compact"}}}}}
(+3)

Worth noting this is pretty much obsoleted now since the new version supports coloured text fields natively. Although I guess the drop shadow one could still come in handy

(or you could just put one field behind the other offset up and to the left, and make the top field transparent)

Yeah, I will still keep using the shadowtext widget because I think it's probably less fiddly than doing it by hand and I only use it for titles and buttons, but main body text in my current project mostly will get redone with the new field because it's easier to work with and supports links. Swings and roundabouts, as they say. 

(+3)

Hi there! I'm trying to use the marquee contraption, but it doesn't seem to save the font, only the text. Am I missing something?

(+3)

oop, figured it out after fiddling with the menu. need to change the font via the widgets menu instead

(+1)

Good day, how can I remove a contraption template?

(+2)

Nevermind, I think I found it! It was on the "Resources" stuff in the "File" menu.

Developer(+7)

The Lockbox Contraption

A simple, unobtrusive contraption that both indicates whether a deck is locked and allows the user to lock or unlock their deck by clicking on it:


Many decks benefit presentationally from being locked, but leaving your decks unlocked helps other deckbuilders learn from your work and (when appropriate) modify it for their own needs. Including this little contraption offers a nice compromise: in a game, you might add this button to the credits screen as a reward for succeeding. Tools and tutorials might offer it on the front page!

%%WGT0{"w":[{"name":"lockbox1","type":"contraption","size":[20,20],"pos":[210,146],"def":"lockbox","widgets":{"c":{},"b":{},"ims":{}}}],"d":{"lockbox":{"name":"lockbox","size":[20,20],"margin":[1,1,2,2],"description":"Make your deck manually lockable and unlockable.","script":"on view do\n i:ims.images[deck.locked]\n c.clear[]\n c.paste[i .5*c.size-i.size]\nend","attributes":{"name":[],"label":[],"type":[]},"widgets":{"c":{"type":"canvas","size":[20,20],"pos":[0,0],"locked":1,"volatile":1,"border":0,"scale":1},"b":{"type":"button","size":[20,20],"pos":[0,0],"script":"on click do\n deck.locked:!deck.locked\n view[]\nend\n","show":"transparent","style":"invisible"},"ims":{"type":"field","size":[100,20],"pos":[154,-5],"locked":1,"show":"none","value":{"text":["","i","i"],"font":["","",""],"arg":["","%%IMG0ABAAEAAAP/xAAkPCR+JGYkZiQGJP8k/yT/JP8k/yQAI//AAA","%%IMG0ABAAEAAAP/xAAkACQ8JH4kZiRmJP8k/yT/JP8k/yQAI//AAA"]}}}}}}
(+2)

ooooooh, this looks simple and nice!

(+2)

This is fantastic; thank you!

(5 edits) (+2)

The Slider Knob

I have always had a fondness for the little slider knob that Apple used in the early Mac control panel, and it certainly feels like it fits the Decker aesthetic, but we just have the scrollbar-y looking ones. So I made this today instead of actually writing.


The slider holds a "value" like any other, but because it's so chunky, it only goes from 0 to 6, because that's exactly as many as I needed for the thing I built it for, and also I think that's exactly how many steps the original inspiration had too. It's not draggable, but it is clickable. Clicking one of the ticked areas sets it to that value, while clicking the top and bottom ends of the slider will increment or decrement the value by one. There is also a "change" event that receives the new value.

Hopefully this is useful to someone. The implementation is pretty crude, and could probably be refactored and maybe even made resizable, and the "sprites" are all there in the script so you could probably make it smaller or larger or whatever.

%%WGT0{"w":[{"name":"vertSlider1","type":"contraption","size":[48,144],"pos":[454,99],"script":"on change val do\n vs.text:val+0\nend","def":"vertSlider","widgets":{"sliderVal":{},"can":{},"buttonTop":{},"buttonBottom":{},"button1":{},"button2":{},"button3":{},"button4":{},"button5":{},"button6":{},"button7":{}}}],"d":{"vertSlider":{"name":"vertSlider","size":[48,144],"margin":[0,0,0,0],"description":"Classicly inspired vertical slider widget, created for use in the tension track.","script":"sliderTop:image[\"%%IMG2ADAAEAD/AGYBBgAoAQIgBgECACUBASADAQQgAwEBACMBASACAQMgAgEDIAIBAQAiAQEgAQECIAYBAiABAQEAIQEBIAIBASAIAQEgAgEBACABASABAQIgAwECIAMBAiABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABA=\"]\nsliderT:image[\"%%IMG2ADAAEAAQAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAHwESAB0BASASAQEAHAEBIBIBAQAbARYAGQEBIBYBAQATAQQAAQEBIAEBFCABAQEAAQEEAA4BBAABAQEgAQEUIAEBAQABAQQAEwEBIBYBAQAZARYAGwEBIBIBAQAcAQEgEgEBAB0BEgAfAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAEA==\"]\nsliderF:image[\"%%IMG2ADAAEAAQAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAQ\"]\nsliderBottom:image[\"%%IMG2ADAAEAAQAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBAiADAQIgAwECIAEBAQAgAQEgAgEBIAgBASACAQEAIQEBIAEBAiAGAQIgAQEBACIBASACAQMgAgEDIAIBAQAjAQEgAwEEIAMBAQAlAQIgBgECACgBBgD/AGY=\"]\n\non get_value do sliderVal.text+0 end\non set_value v do sliderVal.text:v end\n\non view do\n can.clear[]\n can.paste[sliderTop 0,0]\n can.paste[sliderBottom 0,128]\n \n each x in range 7\n  can.paste[sliderF 0,16+(x*16)]\n end\n \n can.paste[sliderT 0,16+(get_value[]*16)]\nend\n\non change val do\n sliderVal.text:val\n card.event[\"change\" val]\n view[]\nend","template":"on change val do\n \nend","image":"%%IMG2ADAAkAACIAIABiACAAYgAQAEIAEAFSABABkgBwABIA8ADCACAAYgAQAaIAIACyACAAYgAQAZIAEAAiABAAogAgAGIAEAGCABAAcgAwABIAMAASADAAUgAwAUIAEABCABAAIgAQABIAIAASAEAAEgAgAEIAQABiABAAwgAgAHIAIABiACAAkBBgANIAMAByACAAYgAgAHAQIABCACAQIABCABAAUgAQABIAIAFwEBAAMBBCABAAIBAQABIAEAGyABAAUBASACAQMgAgEDAAIBASAEAAQgAQATIAEABQEBAAEBAiABAAUBAgABAQEgAQABIAEABiABABIgAQAEAQEAASABAQEAASABAAYBAQABIAEBAQAJIAEAASACABMBASABAQIgAgABAQIAAwECAAEBAQAKIAEABCABAAsgAQAEAQEgAQEBIAEAASABAQQAAwEBIAEBAQALIAEADyABAAQBAQABAQEAAwEEAAMBAQABAQEADCABAAIgAQAQAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAVAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAVAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAVAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAVAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAVAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAVAQEAAQEBAAMBBAADAQEAAQEBAA0gAgARAQEAAQEBAAMBBAADAQEAAQEBACABAQABAQEAAwEEAAMBAQABAQEACiABAAkgAQACIAEABSABAAEgAQEBAAEBAQADAQQAAwEBAAEBASABAAEgAQAFIAEAAiABAAggAQACIAEAASACAAQgAQEBAAEBAQADAQQAAwEBAAEBASABAAQgAgABIAEAASADAAcgAQAEIAIABQEBAAEBAQADAQQAAwEBAAEBAQAFIAIAAyADABMBAQABAQEAAwEEAAMBAQABAQEAAiABAAkgAQACIAEABSABAAEBBAAFAQEAAQEBAAMBBAADAQEAAQEBAAIgAQACAQQABiABAAQgAQACAQQABQEBAAEBAQADAQQAAwEBAAEBAQAFAQQAFwEBAAEBAQADAQQAAwEBAAEBAQAXIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAogAQABIAEACAEBAAEBAQADAQQAAwEBAAEBASABAAcgAQABIAEACSABAAIgAQAIAQEAAQEBAAMBBAADAQEAAQEBIAEAByABAAEgAQAMIAEACAEBAAEBAQADAQQAAwEBAAEBAQAIIAEAASABAAkgAgABIAEABSABAAIBAQABAQEAAwEEAAMBAQABAQEAAiABAAUgAQABIAEACSACAAEgAQAFIAEAAgEBAAEBAQADAQQAAwEBAAEBAQACIAEABSABAAEgAQAIIAEAAiABAAQgAQAEAQEAAQEBAAMBBAADAQEAAQEBAAUgAQAJIAIAAiABAAIgAQAEIAEABAEBIAEBASABAAEgAQEEAAMBASABAQEABSADAAggAQACIAEAAiABAAQgAQAEAQEgAQECIAIAAQECAAMBAgABAQEABSADAAkgAQABIAEAAiABAAIgAQABIAEABAEBAAEgAQEBAAEgAQAGAQEAASABAQEgAQAEIAEACCACAAEgAwACIAEAASAEAAUBAQABAQIgAQAFAQIAAQEBIAEAASABAAMgAQACIAIABCABAAQgAQACIAEABCABAAUBASACAQMgAgEDAAIBASACAAQgAQAIIAIAEgEBAAMBBCABAAIBAQABIAIAIgECAAQgAgECABsgAQAMAQYADCACAA4gAQANIAEABCABAAwgAQAIIAIAEyABAAIgAQABIAMACCABAAEgAgAHIAIABSABAA0gAQACIAEAAiACAAkgAQAGIAEAASABAAcgAQANIAEAASADAAEgAwAIIAEAAiABAAQgAQAIIAMABiAGAAEgAQABIAMAASABAAkgAgAZIAEABCABAAEgAgACIAEAASABACAgBQACIAcAASACAA8=","attributes":{"name":["value"],"label":["Value"],"type":["string"]},"widgets":{"sliderVal":{"type":"field","size":[21,20],"pos":[57,1],"show":"none","border":1,"value":"0"},"can":{"type":"canvas","size":[48,144],"pos":[0,0],"locked":1,"border":0,"image":"%%IMG2ADAAkAD/AGYBBgAoAQIgBgECACUBASADAQQgAwEBACMBASACAQMgAgEDIAIBAQAiAQEgAQECIAYBAiABAQEAIQEBIAIBASAIAQEgAgEBACABASABAQIgAwECIAMBAiABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAfARIAHQEBIBIBAQAcAQEgEgEBABsBFgAZAQEgFgEBABMBBAABAQEgAQEUIAEBAQABAQQADgEEAAEBASABARQgAQEBAAEBBAATAQEgFgEBABkBFgAbAQEgEgEBABwBASASAQEAHQESAB8BASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBAiADAQIgAwECIAEBAQAgAQEgAgEBIAgBASACAQEAIQEBIAEBAiAGAQIgAQEBACIBASACAQMgAgEDIAIBAQAjAQEgAwEEIAMBAQAlAQIgBgECACgBBgD/AGY=","scale":1},"buttonTop":{"type":"button","size":[48,16],"pos":[0,0],"script":"on click do\n v:sliderVal.text+0\n if v\n  sliderVal.text:v-1\n end\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"buttonBottom":{"type":"button","size":[48,16],"pos":[0,128],"script":"on click do\n v:sliderVal.text+0\n if v<6\n  sliderVal.text:v+1\n end\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button1":{"type":"button","size":[48,16],"pos":[0,16],"script":"on click do\n sliderVal.text:0\n card.event[\"change\" get_value[]] \n view[]\nend","style":"invisible"},"button2":{"type":"button","size":[48,16],"pos":[0,32],"script":"on click do\n sliderVal.text:1\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button3":{"type":"button","size":[48,16],"pos":[0,48],"script":"on click do\n sliderVal.text:2\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button4":{"type":"button","size":[48,16],"pos":[0,64],"script":"on click do\n sliderVal.text:3\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button5":{"type":"button","size":[48,16],"pos":[0,80],"script":"on click do\n sliderVal.text:4\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button6":{"type":"button","size":[48,16],"pos":[0,96],"script":"on click do\n sliderVal.text:5\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button7":{"type":"button","size":[48,16],"pos":[0,112],"script":"on click do\n sliderVal.text:6\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"}}}}}
(+2)

Hah, forgot to lock the canvas and discovered you can "scratch" the slider if you do try to drag it. Fixed that. :P

(1 edit) (+2)

In the process of making a horizontal version I discovered the transparency mask on the slider is a mess because the card I used got all polluted by some sprite assets I subsequently removed. I've fixed the paste and also here's that horizontal one!

%%WGT0{"w":[{"name":"hSlider1","type":"contraption","size":[144,48],"pos":[358,244],"script":"on change val do\n hs.text:val\nend","def":"hSlider","widgets":{"sliderVal":{},"can":{},"buttonTop":{},"buttonBottom":{},"button1":{},"button2":{},"button3":{},"button4":{},"button5":{},"button6":{},"button7":{}}}],"d":{"hSlider":{"name":"hSlider","size":[144,48],"margin":[0,0,0,0],"description":"Horizontal version of the vertSslider widget.","script":"sliderTop:image[\"%%IMG2ADAAEAD/AGYBBgAoAQIgBgECACUBASADAQQgAwEBACMBASACAQMgAgEDIAIBAQAiAQEgAQECIAYBAiABAQEAIQEBIAIBASAIAQEgAgEBACABASABAQIgAwECIAMBAiABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABA=\"].transform[\"left\"]\nsliderT:image[\"%%IMG2ADAAEAAQAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAHwESAB0BASASAQEAHAEBIBIBAQAbARYAGQEBIBYBAQATAQQAAQEBIAEBFCABAQEAAQEEAA4BBAABAQEgAQEUIAEBAQABAQQAEwEBIBYBAQAZARYAGwEBIBIBAQAcAQEgEgEBAB0BEgAfAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAEA==\"].transform[\"left\"]\nsliderF:image[\"%%IMG2ADAAEAAQAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBABcBBAAFAQEgAQEBIAMBBCADAQEgAQEBAAUBBAAOAQQABQEBIAEBASADAQQgAwEBIAEBAQAFAQQAFwEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAgAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBASADAQQgAwEBIAEBAQAQ\"].transform[\"left\"]\nsliderBottom:image[\"%%IMG2ADAAEAAQAQEgAQEBIAMBBCADAQEgAQEBACABASABAQEgAwEEIAMBASABAQEAIAEBIAEBAiADAQIgAwECIAEBAQAgAQEgAgEBIAgBASACAQEAIQEBIAEBAiAGAQIgAQEBACIBASACAQMgAgEDIAIBAQAjAQEgAwEEIAMBAQAlAQIgBgECACgBBgD/AGY=\"].transform[\"left\"]\n\non get_value do sliderVal.text+0 end\non set_value v do sliderVal.text:v end\n\non view do\n can.clear[]\n can.paste[sliderTop 0,0]\n can.paste[sliderBottom 128,0]\n \n each x in range 7\n  can.paste[sliderF (16+x*16),0 1]\n end\n \n can.paste[sliderT (16+get_value[]*16),0 1]\nend\n\non change val do\n sliderVal.text:val\n card.event[\"change\" val]\n view[]\nend","template":"on change val do\n \nend","attributes":{"name":["value"],"label":["Value"],"type":["string"]},"widgets":{"sliderVal":{"type":"field","size":[21,20],"pos":[160,0],"show":"none","border":1,"value":"0"},"can":{"type":"canvas","size":[144,48],"pos":[0,0],"locked":1,"script":"on click pos do\n \nend\n\non drag pos do\n \nend\n\non release pos do\n \nend","show":"transparent","border":0,"image":"%%IMG2AJAAMAD/AP8A/wD/AAsBAgAOAQIADgECAA4BAgAOAQIADgECAA4BAgAuAQIADgECAA4BAgAOAQIADgECAA4BAgAOAQIALgECAA4BAgAOAQIADgECAA4BAgAOAQIADgECAC4BAgAOAQIADgECAA4BAgAOAQIADgECAA4BAgC9AQQAiwEBIAQBAQCIAQMgAQECIAEBAwCFAQEgAgEBIAEBAiABAQEgAgEBAH4BByACAQEgAQECIAEBASACAWcAFgECIAYBASACAQEgAQECIAEBASACAQEgZgECABMBASADAQYgAgEBIAEBAiABAQEgAgFmIAMBAQARAQEgAgEDIAQBASACAQEgAQECIAEBASACAQEgZAEDIAIBAQAQAQEgAQECIAYBASACAQEgAQECIAEBASACAQEgZgECIAEBAQAPAQEgAgEBIAcBASACAQEgAQECIAEBASACAQEgZwEBIAIBAQAOAQEgAQECIAMBBSACAQEgAQECIAEBASACAWUgAwECIAEBAQAOAQEgAQEBIAMBBiACAQEgAQECIAEBASACAWYgAwEBIAEBAQAOAQEgAQEBIAMBBiACAQEgAQECIAEBASACAWYgAwEBIAEBAQAOAQEgAQECIAMBBSACAQEgAQECIAEBASACAWUgAwECIAEBAQAOAQEgAgEBIAcBASACAQEgAQECIAEBASACAQEgZwEBIAIBAQAPAQEgAQECIAYBASACAQEgAQECIAEBASACAQEgZgECIAEBAQAQAQEgAgEDIAQBASACAQEgAQECIAEBASACAQEgZAEDIAIBAQARAQEgAwEGIAIBASABAQIgAQEBIAIBZiADAQEAEwECIAYBASACAQEgAQECIAEBASACAQEgZgECABYBByACAQEgAQECIAEBASACAWcAHgEBIAIBASABAQIgAQEBIAIBAQCFAQMgAQECIAEBAwCIAQEgBAEBAIsBBAD/AB4BAgAOAQIADgECAA4BAgAOAQIADgECAA4BAgAuAQIADgECAA4BAgAOAQIADgECAA4BAgAOAQIALgECAA4BAgAOAQIADgECAA4BAgAOAQIADgECAC4BAgAOAQIADgECAA4BAgAOAQIADgECAA4BAgD/AP8A/wD/AAs=","scale":1},"buttonTop":{"type":"button","size":[16,48],"pos":[0,0],"script":"on click do\n v:sliderVal.text+0\n if v\n  sliderVal.text:v-1\n end\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"buttonBottom":{"type":"button","size":[16,48],"pos":[128,0],"script":"on click do\n v:sliderVal.text+0\n if v<6\n  sliderVal.text:v+1\n end\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button1":{"type":"button","size":[16,48],"pos":[16,0],"script":"on click do\n sliderVal.text:0\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button2":{"type":"button","size":[16,48],"pos":[32,0],"script":"on click do\n sliderVal.text:1\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button3":{"type":"button","size":[16,48],"pos":[48,0],"script":"on click do\n sliderVal.text:2\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button4":{"type":"button","size":[16,48],"pos":[64,0],"script":"on click do\n sliderVal.text:3\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button5":{"type":"button","size":[16,48],"pos":[80,0],"script":"on click do\n sliderVal.text:4\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button6":{"type":"button","size":[16,48],"pos":[96,0],"script":"on click do\n sliderVal.text:5\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"},"button7":{"type":"button","size":[16,48],"pos":[112,0],"script":"on click do\n sliderVal.text:6\n card.event[\"change\" get_value[]]\n view[]\nend","style":"invisible"}}}}}
(+2)

And now they have a "change" event because I needed one! 

(1 edit) (+1)

A tabstrip contraption

image.png image.png

I have a card that calculates some data, and displays it in various ways. Rather than have multiple cards that do the same calculation, I figured I’d have all of the views on the same card, and add a tabstrip to switch which ones were visible.

Attributes:

  • x.labels String. The text of the labels in the tabstrip, separated by \n. r/w.
  • x.current String. The text of the currently selected label. r/w.

Events:

  • on change label active Called when a tab is activated or deactivated. label (string) is the label of the tab that changed, active (bool) is true if the tab became active, or false if the tab became inactive.

The thing I’m proud of is the event model. Previously, I had separate Decker buttons for each tab, so when I added a new widget to a “tab” I had to add newwidget.show:"solid" on one button and newwidget.show:"none" on all the others, and I kept forgetting which buttons I’d updated, copy/pasting the line and forgetting to change "show" to "none" or vice-versa, it was a pain.

The new tabstrip contraption sends an event for the old tab deactivating, and an event for the new tab activating, so I can have one single event handler like this:

on change label active do
    if label = "Words"
        field1.show:if active "solid" else "none" end
    elseif label = "Picture"
        canvas1.show:if active "solid" else "none" end
    end
end

…and when I add a new widget, I can add just one line to one event handler, and be sure it will never be out of sync with anything else.

One awkward thing is that you wind up with different widgets overlapping, so you can’t easily click on one to select it. As a work around, you can use Widgets → Order… to bring up a list of widgets on the screen, select the widget you want to work with, and click the “Properties” button (if that’s what you want to do) or just click OK and drag the resize handles around.

%%WGT0{"w":[{"name":"tabstrip","type":"contraption","size":[192,16],"pos":[128,64],"script":"on change label active do\n    if label = \"Words\"\n        field1.show:if active \"solid\" else \"none\" end\n    elseif label = \"Picture\"\n        canvas1.show:if active \"solid\" else \"none\" end\n    end\nend","def":"tabstrip","widgets":{"canvas":{"size":[192,16],"font":"menu","pattern":47},"current":{"pos":[0,32],"value":"Words"},"labels":{"pos":[0,64],"value":"Words\nPicture"}}},{"name":"field1","type":"field","size":[192,80],"pos":[128,80],"scrollbar":1,"value":"Here are some words in a regular field!"},{"name":"canvas1","type":"canvas","size":[192,80],"pos":[128,80],"show":"none","image":"%%IMG2AMAAUAD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AAoBAwDAAQYAwAEGAMABBADAAQQAKgEBAJUBBAAmAQEAmQEEAAUBCgATAQEAnQEFAAoBBQANAQEAnwEGAA0BBAAJAQEAnQECAAYBBAANAQMABQEBAJ0BAQAMAQMADQEFAJ0BAQAQAQIArAEBABMBAwCoAQEAFwECAKUBAQAaAQIAogEBAB0BAQChAQEAHgECAJ4BAQAhAQEAnQEBACIBAQCbAQEAIwEBAJsBAQAkAQEAmQEBACUBAQCZAQEAJgEBAJkBAQAlAQEAmQEBACYBAQCZAQEAJQEBAJkBAQAlAQEAmgEBACQBAQCbAQEAJAEBAJsBAQAjAQEAmwEBACMBAQCcAQEAIQEBAJ4BAQAgAQEAnwEBAB8BAQCgAQIAHAEBAKMBAgAaAQEApQEBABkBAQCmAQIAFgEBAKkBAQAVAQEAqgECABIBAQCtAQIADwEBALABAgALAQIAswEEAAQBAwC5AQQA/wD/AJ0=","scale":1}],"d":{"tabstrip":{"name":"tabstrip","size":[192,32],"resizable":1,"margin":[0,0,0,0],"description":"A strip of mutually-exclusive options that can be clicked.","script":"on get_labels do\n   labels.text\nend\n\non set_labels x do\n   labels.text:x\n   new_labels:\"\\n\" split x\n   if !(current.text in new_labels)\n       set_current[first new_labels]\n   end\nend\n\non get_current do\n   current.text\nend\n\non set_current x do\n   valid_labels:\"\\n\" split labels.text\n   if !(x in valid_labels)\n       x:first valid_labels\n   end\n   card.event[\"change\" current.text 0]\n   current.text:x\n   card.event[\"change\" current.text 1]\n   view[]\nend\n\non view do\n    canvas.pattern:colors.white\n    canvas.rect[(0,0) canvas.lsize]\n    valid_labels:\"\\n\" split labels.text\n    width:canvas.lsize[0] / count valid_labels\n    height:canvas.lsize[1]\n    \n    canvas.font:\"menu\"\n\n    each val key in valid_labels\n        left:key * width\n        canvas.pattern:colors.black\n        if val = current.text\n            canvas.rect[(left,0) width,height]\n            canvas.pattern:colors.white\n        end\n        canvas.text[\n            val\n            (left,0) + (width,height)/2\n            \"center\"\n        ]\n   end\nend","template":"on change label active do\n \nend","attributes":{"name":["labels","current"],"label":["Labels (one per line)","Current Label"],"type":["code","string"]},"widgets":{"canvas":{"type":"canvas","size":[192,32],"pos":[0,0],"volatile":1,"script":"on activate pos do\n    valid_labels:\"\\n\" split labels.text\n    index:floor (pos[0]/canvas.lsize[0])*(count valid_labels)\n    set_current[valid_labels[index]]\nend\n\non click pos do\n    activate[pos]\nend\n\non drag pos do\n    activate[pos]\nend\n\non release pos do\n    activate[pos]\nend","border":0,"scale":1},"current":{"type":"field","size":[96,16],"pos":[0,48],"style":"plain"},"labels":{"type":"field","size":[96,80],"pos":[0,80],"style":"plain"}}}}}
Developer (1 edit) (+1)

You could mildly simplify your "on change" logic by using widget.toggle:

on change label active do
 if label = "Words"
  field1.toggle["solid" active]
 elseif label = "Picture"
  canvas1.toggle["solid" active]
 end
end

If you're frequently changing the set of widgets affected, it might also be worth considering a data-driven approach: form a dictionary mapping labels to lists of widgets, and then toggle entire lists:

on change label active do
 wids.Words:   field1,field2
 wids.Picture: canvas1,canvas2
 wids[label]..toggle["solid" active]
end

And in principle, with a somewhat different contract, you could even lift the toggling up to the tabstrip itself, just leaving the user code to construct such a dictionary. This would, of course, be somewhat less flexible.

(+1)

You could mildly simplify your “on change” logic by using widget.toggle…

Wow, how did I miss that? I should have more faith that Decker provides the kinds of features I’m looking for.

If you’re frequently changing the set of widgets affected, it might also be worth considering a data-driven approach…

Oooh, I shall do exactly that!

And in principle, with a somewhat different contract, you could even lift the toggling up to the tabstrip itself…

That did occur to me, but it wasn’t clear to me that a script could reach outside the contraption to toggle the visibility of other widgets on the card. If I have to write an event handler on the target card anyway, it’s already pretty easy, and you’ve just made it easier! And, as you note, this way it can be useful for things other than just toggling widgets, like an alternative to radio-button groups.

Viewing posts 21 to 35 of 35 · Previous page · First page