9

Background: consider the following code-snippet.

  Dynamic@Grid[
    Table[Setter[Dynamic[idx, (idx = #1) &],
      i*6 + j, 
    Graphics[{Blue, Disk[]}, ImageSize -> 20]], 
    {i, 0, 1}, {j, 6}]]

This code creates two rows of clickable disk images. So if idx=10 is run, the 10th disk looks pressed. I want to make this control multi-selectable. So if idx={1,12} run, the first and last disks look pressed. ( In my application the disks may have different colors, edge properties and opacity. ) - See also: What is an efficient way of selecting multiple colors via Manipulate?

Question: How to create "a multi-selectable setterbar with colored buttons" ? ( preferably based on the snippet above, but not necessarily ).

nilo de roock
  • 9,657
  • 3
  • 35
  • 77

3 Answers3

7

Does this provide the functionality you are looking for? Note that a multi-selectable SetterBar is a TogglerBar. The only problem with the latter is that it cannot be partitioned into a multi-row grid. For your particular problem, I would rather use Button instead of Setter:

list = {};
Dynamic@list

Grid[Table[
   DynamicModule[{pressed = False}, With[{idx = i*6 + j},
     Button[Graphics[{Blue, Disk[]}, ImageSize -> 20], 
      pressed = ! pressed; 
      list = If[pressed, Append[list, idx], DeleteCases[list, idx]], 
      Appearance -> Dynamic@If[pressed, "Pressed", Automatic]]]],
   {i, 0, 1}, {j, 6}]]

Mathematica graphics

A somewhat different approach is to concatenate multiple TogglerBars: this has some drawbacks, as the output is always sorted (if not then output order depends on the order of clicks and the order of TogglerBar rows).

TogglerGrid::usage = 
  "TogglerGrid[x, {val.1, val.2, ...}, n] represents a \
TogglerBar-like control (with setting x and with toggler buttons for \
values val.i to include in the list x), but with togglers arranged in \
a grid, with a maximal n elements per row.";

TogglerGrid[var_, ref_] := TogglerGrid[var, ref, Length@ref];
TogglerGrid[Dynamic[var_], list_List, n_] := Module[
   {set, ref = Evaluate@list, temp},
   temp = {} & /@ ref;
   set = TogglerBar[
       Dynamic[temp[[#]], 
        Function[{$x}, temp[[#]] = $x; 
         var = Sort@(Join @@ temp)]], {ref[[#]]}] & /@ 
     Range@Length@ref;
   Grid[
    Partition[set, n, n, {1, 1}, {}],
    Alignment -> {Center, Center},
    Spacings -> {0, 0}]
   ];
TogglerGrid[var_, arg___] := 
  Module[{dummy = var}, TogglerGrid[Dynamic@dummy, arg]];

Test the function:

x = {};
Dynamic@x
TogglerGrid[Dynamic[x], 
 Table[Graphics[{Hue@RandomReal[], Disk[]}, ImageSize -> 20], {10}],
  5]

Mathematica graphics

István Zachar
  • 47,032
  • 20
  • 143
  • 291
2

Starting at least in M9, TogglerBar supports an Appearance option that produces a grid:

DynamicModule[{idx = {}},
    {
    TogglerBar[
        Dynamic[idx],
        Table[i -> Graphics[{Blue, Disk[]}, ImageSize->20], {i, 12}],
        Appearance -> "Horizontal" -> {2, Automatic}
    ],
    Dynamic[idx]
    }
]

enter image description here

where I show an image after clicking a few times.

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
0

In the following, I tried to start with the complete list, with sorting, and deleting duplicates. It works except that you have to click twice the first time on each number. Can this be fixed? It would also be nice if the button changed color to red when off. I tried, but couldn't get it to work. And if each circle had its number in it.

n = 12;
list = Range[n];
Dynamic@list

gOn = Show[Graphics[{Blue, Disk[]}], ImageSize -> 20]; gOff = Show[Graphics[{Red, Disk[]}], ImageSize -> 20]; this = {gOn, gOff};

tb01 = Table[Show[gOn , Graphics[{Text[Style[ToString[k], White, Bold]]}]], {k, 1, 12}] tb02 = Table[Show[gOff, Graphics[{Text[Style[ToString[k], White, Bold]]}]], {k, 1, 12}]

flags = ConstantArray[1, n];

Grid[Table[DynamicModule[{pressed = False, hold = i*6 + j, that}, With[{idx = hold}, If[flags[[hold]] == 1, that = tb01[[hold]], that = tb02[[hold]]]; Button[that, pressed = ! pressed; list = DeleteDuplicates[ Sort[If[pressed, Append[list, idx], DeleteCases[list, idx]]]], Appearance -> Dynamic@If[pressed, "Pressed", Automatic]]]], {i, 0, 1}, {j, 6}]]

user48879
  • 91
  • 5