4
$\begingroup$

Let's say I have a workflow that involves importing images and turning them into an animated gif.

Here's how I currently have it setup:

Import Images:

imports = {};
importimages[] := Module[{a},
   a = SystemDialogInput["FileOpen"];
   If[ListQ[a], Table[Import[a[[i]]], {i, 1, Length[a]}], Import[a]]]
imports = Flatten[Append[imports, importimages[]]]

Allow for selection and rearranging:

sels = Range[Length[imports]];
CheckboxBar[Dynamic[sels], Table[i -> imports[[i]], {i, 1, Length[imports]}]]
imgs = Dynamic[imports[[sels]]]

Set animation rate and preview:

Manipulate[
  displayrate = 1/rate;
  ListAnimate[Setting[imgs], AnimationRate -> rate, AnimationRunning -> False],
  {{rate, 1}, 0, 10, 0.1, LocalizeVariables -> False}]

Export to gif:

Export["~//Desktop//test.gif", Setting[imgs], "DisplayDurations" -> displayrate]

(By the way, feel free to improve code.)

My question is, what is the best way I can smoothly and dynamically wrap this entire workflow into a graphical program where if I were to put a non-Mathematica user in front of it, he/she can easily work it?

This question mainly stems from my poor understanding of the dynamic constructs and roots in action-based programming. The gif routine is just an example for future implementations that involve concise sequential steps.

$\endgroup$
3
$\begingroup$

Here's something I made. The best part is the sound effects. LOL.

image selector/swapper

My goal here is just to show some of the stuff you can do. If you click on 2 pictures it will swap their positions. If you right-click on a picture it will be removed. I didn't implement the animation/export stuff but I think something along the lines of this is a good approach. And in terms of sequential operations, I think the real answer to your question is the Buttons I'm using.

swap = {};
images = {};

combobulate[img_Image, index_] := DynamicModule[{color = White},
   EventHandler[
    Panel[img, ImageSize -> {80, {80}}, Alignment -> Center, Background -> Dynamic[color]],
    {{"MouseClicked", 1} :> (
       Switch[Length[swap],
        0, color = Lighter@Purple; swap = {index},
        1, If[swap[[1]] == index,
         color = White; swap = {},
          images[[{swap[[1]], index}]] = images[[{index, swap[[1]]}]];
         EmitSound[Sound[SoundNote[12]]];
          swap = {}]]),
     {"MouseClicked", 2} :> (
       swap = {};
       Speak["deleted"];
       images = Delete[images, index];
       )}]
   ];

Column@{
  Panel[Row@{
     Button["Add",
       images = Join[images, Cases[
          Quiet[Import /@ Flatten[List[SystemDialogInput["FileOpen"]]]], _Image]],
       Method -> "Queued"], (* so that file loading doesn't time out *)

     Button["Clear", images = {}]}],

  Panel[
   Dynamic[Row@MapIndexed[combobulate[#1, #2[[1]]] &, images]]]}

One thing to note about how the image panel updates: When 2 images have been clicked on, those images have their positions swapped in the base images list. The Dynamic on the last line detects this change in images, and so it re-does the combobulate on all the images. This has the effect of reallocating the indices, so we don't have to worry about keeping track of them. We just shuffle things around however we want and it all gets refreshed.

A more general point is that Manipulate itself is built up from Dynamic. Manipulate doesn't have any special powers. At least not any obvious ones. You could construct your own Manipulate if you wanted to. Also: You can place buttons and stuff in the control regions of Manipulate.

$\endgroup$
  • $\begingroup$ Ha. Speak["deleted"]. I'll accept just for this alone. Thanks for the help. $\endgroup$ – kale Sep 30 '12 at 0:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.