From 423eb378278e851d95b2657621b5c28d07cec660 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Tue, 23 Sep 2014 22:01:27 -0700 Subject: [PATCH 01/36] Swing tutorials under examples. --- .../tutorials/TextSamplerDemoHelp.html | 32 ++ .../examples/tutorials/images/Back24.gif | Bin 0 -> 422 bytes .../swing/examples/tutorials/images/Bird.gif | Bin 0 -> 5377 bytes .../swing/examples/tutorials/images/Cat.gif | Bin 0 -> 3366 bytes .../swing/examples/tutorials/images/Dog.gif | Bin 0 -> 3587 bytes .../swing/examples/tutorials/images/FD.jpg | Bin 0 -> 2339 bytes .../examples/tutorials/images/Forward24.gif | Bin 0 -> 434 bytes .../examples/tutorials/images/Open16.gif | Bin 0 -> 228 bytes .../swing/examples/tutorials/images/Pig.gif | Bin 0 -> 8613 bytes .../examples/tutorials/images/Rabbit.gif | Bin 0 -> 6220 bytes .../examples/tutorials/images/Save16.gif | Bin 0 -> 206 bytes .../swing/examples/tutorials/images/Up24.gif | Bin 0 -> 429 bytes .../swing/examples/tutorials/images/blue.gif | Bin 0 -> 13061 bytes .../examples/tutorials/images/doggy/T0.gif | Bin 0 -> 4955 bytes .../examples/tutorials/images/doggy/T1.gif | Bin 0 -> 4747 bytes .../examples/tutorials/images/doggy/T10.gif | Bin 0 -> 4660 bytes .../examples/tutorials/images/doggy/T11.gif | Bin 0 -> 4775 bytes .../examples/tutorials/images/doggy/T12.gif | Bin 0 -> 3917 bytes .../examples/tutorials/images/doggy/T13.gif | Bin 0 -> 5000 bytes .../examples/tutorials/images/doggy/T2.gif | Bin 0 -> 4301 bytes .../examples/tutorials/images/doggy/T3.gif | Bin 0 -> 4672 bytes .../examples/tutorials/images/doggy/T4.gif | Bin 0 -> 4787 bytes .../examples/tutorials/images/doggy/T5.gif | Bin 0 -> 3926 bytes .../examples/tutorials/images/doggy/T6.gif | Bin 0 -> 5015 bytes .../examples/tutorials/images/doggy/T7.gif | Bin 0 -> 4935 bytes .../examples/tutorials/images/doggy/T8.gif | Bin 0 -> 4759 bytes .../examples/tutorials/images/doggy/T9.gif | Bin 0 -> 4305 bytes .../examples/tutorials/images/dukeWaveRed.gif | Bin 0 -> 1638 bytes .../examples/tutorials/images/flyingBee.jpg | Bin 0 -> 83557 bytes .../tutorials/images/geek/geek-----.gif | Bin 0 -> 4599 bytes .../tutorials/images/geek/geek----t.gif | Bin 0 -> 4685 bytes .../tutorials/images/geek/geek---h-.gif | Bin 0 -> 4736 bytes .../tutorials/images/geek/geek---ht.gif | Bin 0 -> 4849 bytes .../tutorials/images/geek/geek--g--.gif | Bin 0 -> 4762 bytes .../tutorials/images/geek/geek--g-t.gif | Bin 0 -> 4832 bytes .../tutorials/images/geek/geek--gh-.gif | Bin 0 -> 4846 bytes .../tutorials/images/geek/geek--ght.gif | Bin 0 -> 4843 bytes .../tutorials/images/geek/geek-c---.gif | Bin 0 -> 4576 bytes .../tutorials/images/geek/geek-c--t.gif | Bin 0 -> 4699 bytes .../tutorials/images/geek/geek-c-h-.gif | Bin 0 -> 4718 bytes .../tutorials/images/geek/geek-c-ht.gif | Bin 0 -> 4841 bytes .../tutorials/images/geek/geek-cg--.gif | Bin 0 -> 4693 bytes .../tutorials/images/geek/geek-cg-t.gif | Bin 0 -> 4805 bytes .../tutorials/images/geek/geek-cgh-.gif | Bin 0 -> 3675 bytes .../tutorials/images/geek/geek-cght.gif | Bin 0 -> 4997 bytes .../examples/tutorials/images/gifIcon.gif | Bin 0 -> 557 bytes .../swing/examples/tutorials/images/green.gif | Bin 0 -> 12455 bytes .../examples/tutorials/images/jpgIcon.gif | Bin 0 -> 481 bytes .../examples/tutorials/images/kathyCosmo.gif | Bin 0 -> 29844 bytes .../tutorials/images/lainesTongue.gif | Bin 0 -> 63185 bytes .../swing/examples/tutorials/images/left.gif | Bin 0 -> 172 bytes .../examples/tutorials/images/middle.gif | Bin 0 -> 235 bytes .../examples/tutorials/images/pngIcon.png | Bin 0 -> 685 bytes .../swing/examples/tutorials/images/red.gif | Bin 0 -> 12017 bytes .../swing/examples/tutorials/images/right.gif | Bin 0 -> 172 bytes .../swing/examples/tutorials/images/sound.gif | Bin 0 -> 248 bytes .../examples/tutorials/images/stickerface.gif | Bin 0 -> 26850 bytes .../examples/tutorials/images/sunw01.jpg | Bin 0 -> 64004 bytes .../examples/tutorials/images/sunw02.jpg | Bin 0 -> 57300 bytes .../examples/tutorials/images/sunw03.jpg | Bin 0 -> 50526 bytes .../examples/tutorials/images/sunw04.jpg | Bin 0 -> 54051 bytes .../examples/tutorials/images/sunw05.jpg | Bin 0 -> 55490 bytes .../examples/tutorials/images/tiffIcon.gif | Bin 0 -> 565 bytes .../examples/tutorials/images/tumble/T1.gif | Bin 0 -> 1934 bytes .../examples/tutorials/images/tumble/T10.gif | Bin 0 -> 2083 bytes .../examples/tutorials/images/tumble/T11.gif | Bin 0 -> 2011 bytes .../examples/tutorials/images/tumble/T12.gif | Bin 0 -> 2144 bytes .../examples/tutorials/images/tumble/T13.gif | Bin 0 -> 2226 bytes .../examples/tutorials/images/tumble/T14.gif | Bin 0 -> 2090 bytes .../examples/tutorials/images/tumble/T15.gif | Bin 0 -> 1986 bytes .../examples/tutorials/images/tumble/T16.gif | Bin 0 -> 2015 bytes .../examples/tutorials/images/tumble/T17.gif | Bin 0 -> 2115 bytes .../examples/tutorials/images/tumble/T2.gif | Bin 0 -> 1898 bytes .../examples/tutorials/images/tumble/T3.gif | Bin 0 -> 1880 bytes .../examples/tutorials/images/tumble/T4.gif | Bin 0 -> 1989 bytes .../examples/tutorials/images/tumble/T5.gif | Bin 0 -> 1971 bytes .../examples/tutorials/images/tumble/T6.gif | Bin 0 -> 2027 bytes .../examples/tutorials/images/tumble/T7.gif | Bin 0 -> 2076 bytes .../examples/tutorials/images/tumble/T8.gif | Bin 0 -> 1985 bytes .../examples/tutorials/images/tumble/T9.gif | Bin 0 -> 2053 bytes .../swing/examples/tutorials/images/wavy.gif | Bin 0 -> 194 bytes .../examples/tutorials/images/yellow.gif | Bin 0 -> 12354 bytes .../tutorials/components/BorderDemo.scala | 324 +++++++++++ .../tutorials/components/ButtonDemo.scala | 140 +++++ .../tutorials/components/ButtonHtmlDemo.scala | 145 +++++ .../tutorials/components/CheckboxDemo.scala | 201 +++++++ .../components/ColorChooserDemo.scala | 106 ++++ .../tutorials/components/ComboBoxDemo.scala | 134 +++++ .../tutorials/components/ComboBoxDemo2.scala | 158 ++++++ .../tutorials/components/Corner.scala | 41 ++ .../components/CustomComboBoxDemo.scala | 163 ++++++ .../tutorials/components/DialogDemo.scala | 529 ++++++++++++++++++ .../components/DocumentSizeFilter.scala | 68 +++ .../components/FileChooserDemo.scala | 125 +++++ .../components/FormattedTextFieldDemo.scala | 197 +++++++ .../tutorials/components/FrameDemo.scala | 80 +++ .../tutorials/components/FrameDemo2.scala | 328 +++++++++++ .../tutorials/components/HtmlDemo.scala | 133 +++++ .../tutorials/components/IconDemoApp.scala | 242 ++++++++ .../tutorials/components/IntegerEditor.scala | 158 ++++++ .../tutorials/components/LabelDemo.scala | 113 ++++ .../tutorials/components/ListDemo.scala | 197 +++++++ .../tutorials/components/ListDialog.scala | 168 ++++++ .../components/ListDialogRunner.scala | 149 +++++ .../tutorials/components/MenuDemo.scala | 246 ++++++++ .../tutorials/components/MenuGlueDemo.scala | 102 ++++ .../tutorials/components/MenuLookDemo.scala | 216 +++++++ .../tutorials/components/MissingIcon.scala | 82 +++ .../tutorials/components/PasswordDemo.scala | 121 ++++ .../tutorials/components/PopupMenuDemo.scala | 284 ++++++++++ .../components/RadioButtonDemo.scala | 171 ++++++ .../examples/tutorials/components/Rule.scala | 138 +++++ .../tutorials/components/ScrollDemo.scala | 163 ++++++ .../tutorials/components/ScrollDemo2.scala | 166 ++++++ .../components/ScrollablePicture.scala | 106 ++++ .../components/SimpleTableDemo.scala | 124 ++++ .../components/SimpleTableSelectionDemo.scala | 176 ++++++ .../tutorials/components/SizeDisplayer.scala | 153 +++++ .../tutorials/components/SliderDemo.scala | 216 +++++++ .../tutorials/components/SliderDemo2.scala | 215 +++++++ .../tutorials/components/SplitPaneDemo.scala | 145 +++++ .../tutorials/components/SplitPaneDemo2.scala | 135 +++++ .../components/SplitPaneDividerDemo.scala | 133 +++++ .../tutorials/components/TabbedPaneDemo.scala | 126 +++++ .../tutorials/components/TableDemo.scala | 160 ++++++ .../components/TableFTFEditDemo.scala | 169 ++++++ .../tutorials/components/TablePrintDemo.scala | 181 ++++++ .../components/TableSelectionDemo.scala | 273 +++++++++ .../components/TextComponentDemo.scala | 422 ++++++++++++++ .../tutorials/components/TextDemo.scala | 108 ++++ .../components/TextSamplerDemo.scala | 326 +++++++++++ .../tutorials/components/TopLevelDemo.scala | 91 +++ .../tutorials/components/TumbleItem.scala | 289 ++++++++++ .../examples/tutorials/components/Utils.scala | 68 +++ .../tutorials/concurrency/Flipper.scala | 138 +++++ .../examples/tutorials/misc/ActionDemo.scala | 219 ++++++++ .../tutorials/misc/FocusConceptsDemo.scala | 141 +++++ 137 files changed, 9734 insertions(+) create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Back24.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Bird.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Cat.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Dog.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/FD.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Forward24.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Open16.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Pig.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Rabbit.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Save16.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/Up24.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/blue.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T0.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T1.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T10.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T11.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T12.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T13.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T2.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T3.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T4.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T5.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T6.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T7.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T8.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T9.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/dukeWaveRed.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/flyingBee.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-----.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek----t.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek---h-.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek---ht.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek--g--.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek--g-t.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek--gh-.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek--ght.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c---.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c--t.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c-h-.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c-ht.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cg--.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cg-t.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cgh-.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cght.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/gifIcon.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/green.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/jpgIcon.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/kathyCosmo.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/lainesTongue.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/left.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/middle.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/pngIcon.png create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/red.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/right.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/sound.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/stickerface.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/sunw01.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/sunw02.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/sunw03.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/sunw04.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/sunw05.jpg create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tiffIcon.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T1.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T10.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T11.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T12.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T13.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T14.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T15.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T16.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T17.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T2.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T3.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T4.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T5.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T6.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T7.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T8.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T9.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/wavy.gif create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/yellow.gif create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/IntegerEditor.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html b/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html new file mode 100644 index 00000000..36571986 --- /dev/null +++ b/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html @@ -0,0 +1,32 @@ + + + +Styled Text Sample + +Waving Duke icon +

This is an uneditable JEditorPane, +which was initialized +with HTML text from a +URL. +

+An editor pane uses specialized editor kits +to read, write, display, and edit text of +different formats. +The Swing text package includes editor kits +for plain text, HTML, and RTF. +You can also develop +custom editor kits for other formats. + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Back24.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Back24.gif new file mode 100644 index 0000000000000000000000000000000000000000..787518c8ce9b57f2abc04a5679f71be7031bc089 GIT binary patch literal 422 zcmZ?wbhEHblwgoxxcZ;r|Ns9_p8k9M`0vAqzaQNHdH3G;+qb{my!q+o&1cuIf4Fkx z-K9&f&!2yJ_T2N+r=OlY`S|#;2S<!ukYS{b?45@+qYlb zy6ybdt>?FFIlFoDnRV-quUT_!#fpQ=mhE4-VAs5PJ7&$=JY&YjDO1)?oVcpDcUf20 z;6Rvz`$_ezyTmhBvAax!pOj2$e;sK5Au@(Tfu=D1s*z5 z{Vozsivla-7#NDUf?L+G-Y8j}lC|9_!Y$P?a^C}!kXdevZaXhsx-znPcZs!)jG?Iq zZ+>+miyUKBb7xnsS5rZSR%!JF|G*ya%4wMsN@q<@trhI+spnPZT0EOok+n^~+n{}3 zS59|=BZJ~Uf9L#y%A(Blj1mPS0|Ntvq)LV0(mVy<%;ci{;>zNZ)ZAhn1<$->Jq5>{ o9EBi|!eWJ>)Z)~lveXnkUM?>mHwE_~g|O5j1w%apUM>b}04xEyoB#j- literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Bird.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Bird.gif new file mode 100644 index 0000000000000000000000000000000000000000..b8a057716775ba9e0c65b601cabf21c1e6d4685c GIT binary patch literal 5377 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 Xi;HdavWKTwE7EY3Xh@dAz|#K*2xK!W literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Dog.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Dog.gif new file mode 100644 index 0000000000000000000000000000000000000000..e7f030ddee4ad075393ed7b7571523ef03ecf5c8 GIT binary patch literal 3587 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 RA~Z0Yyw^HpbZUqD^4}squIc~) literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Forward24.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Forward24.gif new file mode 100644 index 0000000000000000000000000000000000000000..1936fd4bf9d300479fddb665d2650445adbe9f23 GIT binary patch literal 434 zcmV;j0Zsl#Nk%w1VHf}y0M-8h|NsBy=Ktm8{^R5P;o-}&C%_ubw1+uQZq+w|Gl z^4Zzu*VgdV)b7&K>(J2Y(9h}3&F9O@<;lt8$H(Br#NNWf+`z!hzrfkOzSq0E)VaCS zx3|!>wa>J)&a<=3u&~LluE(sb#j2{qsHnlGr@^JAzoVnQqocf`pt_);x}Ki6oSe0q znzNRcuauOnkB_L0ji!i*p@xQ^f`glZftrATnKLtH0002Mz`y_i000000000000000 z00000A^8LW0021vEC2ui02lxm06+$Oz?^VMEEqNFOwm)DL zUM5f|DAMG)`M?5!8MjshY0h2MsCcKyI-XnYHYZ=p(kDk{gOnH)|M@%T7gQEyre~BW z7#SECC?r)X1efM1_+};-nM2UCF?0T=Hw^@ffN=i1f>?I7L}!@=<#xS W`M4>#2PuT57AY9&8Srv3SOWl92UWNL literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Pig.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Pig.gif new file mode 100644 index 0000000000000000000000000000000000000000..d70eb5633f64ada532e312ae80201dddb9f02530 GIT binary patch literal 8613 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Rabbit.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Rabbit.gif new file mode 100644 index 0000000000000000000000000000000000000000..99ab7e0c7882f5b95b0433d448a7264cbc2a691e GIT binary patch literal 6220 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/Up24.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/Up24.gif new file mode 100644 index 0000000000000000000000000000000000000000..3db88736f7b15ddd5b131f458cb8373ad5032c41 GIT binary patch literal 429 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T0.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T0.gif new file mode 100644 index 0000000000000000000000000000000000000000..e916a218e72d4c0e76c70e2be60415b841e841eb GIT binary patch literal 4955 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 pCe4i$y{ShLJL{6hkx$g-R(G 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 M%Th($ literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T10.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T10.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d9a840f36e5078f0ba00911539bb40f1cd4c0c9 GIT binary patch literal 4660 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T13.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T13.gif new file mode 100644 index 0000000000000000000000000000000000000000..860586d147408090961af503f19fbe4e6a347b9c GIT binary patch literal 5000 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T2.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T2.gif new file mode 100644 index 0000000000000000000000000000000000000000..8a9d1139f5674c12629dd371a5db16e4e2ed5905 GIT binary patch literal 4301 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T3.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T3.gif new file mode 100644 index 0000000000000000000000000000000000000000..d0f820ee71c4c86137d972699dcc881eaa538a52 GIT binary patch literal 4672 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 Qo&q!$_L&={G#U{4e;W8K!T-L;8H&z;w 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 F_J1=Uo6rCN literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T9.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/doggy/T9.gif new file mode 100644 index 0000000000000000000000000000000000000000..d1dd86688be49e0d0c76b6111fdb9b6f0973aec3 GIT binary patch literal 4305 zcmb`G>sJ$p*2afiCl_=O&;bGr7wrg$14K=|&;g}T)a+N)z% z$(E!H0W|O)0O&o00>{l~G#CIV2$aAvT!t!1OhI5W6t?yBm`p00)uf>?wF0x4D`fyg zNTmuKwzktM5R{=PZBSWhlMF>L6vYrotw0ro422*ZbW^&)l`0&8KoSI%q)e4Y?Aen< z$Y5NCsVSMotVtqqnpP1gru=8L%%oDwFcbke6b|DUtR_(d1S@d~jzU8WqaqL#L0U^I z4SFR4a%h!W34&@6RLCR<3@eo+g1|ji6OKw~3e%&QOonM7n808aiDXk01%e2S;2|hQ zpri~ofS`fGOthNBr3egS5KPJt1rfi8jJGok0z)bi#ZVXmL7Sn1+(6)#^$Z#t;c@P~td7)3wvP+N?~rB8k9pH7P}>8BsC_0_}GD(9jSH zgCt49Figmh<(M=+UTQX5OiBy{0FzRtQmJ}+dJqI@Z*Mo57Op3l)@Z_X*^%(9oK3eXe5pWZNJ-k{=qr2F|ID| zTGOKoik8ghcduRe;R@Ad^j_0;@kxvFLDTkoZI_0xt6tu%TXX&L^Bd|v-aNl|{mPHu zYuF;6_;$-km%%kSxv%}|%R5J17j4WZT+-@`XLt<%DTdDL&Q#p~Cf9Y&xr}~tZ$x4f zGk0fmg&<%>!jS2H5tJqTBnJtN7;Y=5Ic^{WqEGK?3Dhqu$C54yMs?Tzs;(v;{V|bv zv|`hlN4aiO6&qb^Bi>{T&nSDH7w)kyN%WUF)K~KE{Mg&r&e3Pew#k@@#6g0ok`U+YIA2Xb94C%I>xKqF>U!9`rMsy>qjnc5Y?yEw| z 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/dukeWaveRed.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/dukeWaveRed.gif new file mode 100644 index 0000000000000000000000000000000000000000..283ef53c479d190ff2df18d2b6b0b61683a0a9bf GIT binary patch literal 1638 zcmdUu|4$QV9LJyX^(bFF3bF$k>+wZfsieh$bUK6zSc?m_GJ_XTut->HB6>Q%oEnr9 zRyh%|>SWa+a4^&=8ZX9eHw%*v)ZH{{)&0<6a4F(gA=%c+l zmaiztQdi`F9N-4P=kp;5f}$vfVK|P<<#LrurBw;TdWo1E;5a~x0HXnJ0+{^G zXP6owt~a-Ej+g*K!aimm5`0VlyMw39G9G}y@<-pDbQ`5a!0g1r~#Q=6iQ#+C1qsCDw{W;$B&AVH0#6A+O(0$197r5 z4yL6$Xyz({5V*;r+j4NS>+XTQ(;`+{n(j_heM#}}qO zsjR6GC*O&b3s1GljoaGIbK`Etb_ZoC*0?vvAm>KgfdXHBx=CCs>acWG=fzeZd@=z1 z0|+^rfdr03FM8#lFZy!L*yyn=B+o9I?lBMnjmoX6yO`vr?s@or`{%zbT~geZ+L1mu zfMfBmI%sevB6U=JBz?5LC{Q~5Tl+f``e3FUk**ATH2<7PbSnLEzV>>3YIXQ?6*5OW zCLY6?<7|!Q+b!vlw%xl@YByW+kheOWH<5mnc8W`>9a8N_kJ5f`(TD$lFrvf1zPI-f>pB&{jbk2TeVH90CCUC8(irb`|ibV2+-TtNVezJ q_9`s7%_B{ZPNCI76Z*@isTbofAB5`nO^sc+_WRU}-b)E6So|-0=oLc% literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/flyingBee.jpg b/examples/src/main/resources/scala/swing/examples/tutorials/images/flyingBee.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a06978eff568cd573461da61ae38bba516550f4 GIT binary patch literal 83557 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%0A5Y&ZL`@}>Um%$tWj-R8~!(Ir8v$tT1? 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 Ve}~ln0Go$Keg21stACrX|Jg;6MS%bS literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-----.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-----.gif new file mode 100644 index 0000000000000000000000000000000000000000..d992b176de4c2409e676653d051ac69489b97954 GIT binary patch literal 4599 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek----t.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek----t.gif new file mode 100644 index 0000000000000000000000000000000000000000..72d0b8e443bd375dd50da2b4d328137e5b0402a5 GIT binary patch literal 4685 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 L$(c9)mrD3AhvDFJ literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek---ht.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek---ht.gif new file mode 100644 index 0000000000000000000000000000000000000000..b86abad1a9063de6cc020e4a767254c9adc410dc GIT binary patch literal 4849 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek--gh-.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek--gh-.gif new file mode 100644 index 0000000000000000000000000000000000000000..643de8f04c9acadc41164e0d0db3fb0def80137f GIT binary patch literal 4846 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 DZ_El* literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c---.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c---.gif new file mode 100644 index 0000000000000000000000000000000000000000..3a79a29643d667203d451a190cf585624d072d4f GIT binary patch literal 4576 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 T`gw2@Oo$nV-+E{`4i^3oOO%&Z literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c--t.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c--t.gif new file mode 100644 index 0000000000000000000000000000000000000000..81ec13d34176c16ad44b6a12cfaf6769647a1e8f GIT binary patch literal 4699 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c-h-.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-c-h-.gif new file mode 100644 index 0000000000000000000000000000000000000000..e5aca555b3213abed9ae0e38d823dbe967d2ac97 GIT binary patch literal 4718 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 Lx(zA87+Cm!22C05 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cg--.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cg--.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff352f62c06b227dd796acce357044ddf04c17fe GIT binary patch literal 4693 zcmXBXc~nzJ+W_#nHw)Pam({RngM=k$A)zkBgu`Z+y1tM09R0XlEG}`(CYD=(cuphqn%XhwWp80RiGtbQPn>lBa z*CxdZwr&IozzG13;}i-7K@b*;6&xJQ<#PFazCa)l3WXAhL@Jfa<#L5WQCL{0QmHf= zjaIAG>-7eM!Duv^OeVA0Y_V8uHrvq9(CFys`1ttr^t99Iv{@_$z20arDCBaR**s*i zNJJuhVq$u9R3sFR+iVu2QRrHR&&NkcxxvA>$;5IML80Jy( zt|(ME<hP$HF# z;-f~JQ793bC(HtoK(3LSoo1n2D3A*DPQ3sZaB;pISEz6e;tV$6MiDLz#s$F1GCM7W zP7NOyS)4XGt}>3A^frUmqL=FxmT8;OX_ly@CZ|P<8%@&|aYFsWe)FP%<=*^93TlK*HsVEH=DQgY!kW$&AYjof5e#aIOHCD{zryS}4K= zLRUr?p9z;K7busn{}(qgfsckUqg)+rP@`2qmIV%GrwcNYK! z2M{GFr2~sE4`SreKW%Q_PxpvU(N{JvJiuTr&AErI|Akx|DEy4I_992E3HdOLXq`wq zli=olLCZxd{13*4Z0M1B%9Gs7x=H`AE>0deno>vW-hRV7e8ZCLg&a!oL|?l%-|_s- zdz0R}Btg)6k)M^u$|-pMv8UN&Wq5oh?7v#~>_cq+p~I_I)StgmN64^O(kAb;Y~+!K zi0a_{{a0c?&wp|*xFTuShszjCS6uq~x5ld63oVJ%I;-->rqG*Y4Bl`*Gf;G4^6o_& z*3j$sR-0xw#1uXs%cVa^>E-R;hzJoXL z;|^GhSEiqjfb7Rd#*k+}n@#Smo1bqp*Zy(sj$ujOZCL^mYp)DL-hX>f+~@v39A(`{ z^AlrJ+z^gf?K(U)Ag_^i{Isj6sO5O(wI|o-fn6XYdH!z3ONM$ZQI2K4x<^1^KkMtD z<$lTp3NfDpU`XL3wi2#xSN?SHL*mf~d*-%=OXB;kWQ*fs2JN-)1J+~1NAp&(Nkopm zu?*xhcxvduY`15A{KM;w`aob$2-fCB0S>syzfCT zWB5Ox2oI(B=nG+8e~_|!h8$Gp)qmT4nN>}QBmD`Z3%0DdzMd48h##3eefS@HA4S5} zwPas{UX5fVZI$ZN-1eW#jQ2)FWyA%sc8Gc@=4z|Qs#VS9P3Bk9woe=OZ+~cf2kQ8c z{>LSyM}d0&@hCSo(S8BobKchXbC}pcpXh#turW?&wSj(R!;wp6K66Km_ltCqZ?KPbMgveJDU8E-DGLAAiX zJa^;q0pe#wuMz-pl@&fjR88|!lic^J(FjL*p-*3apSTX7lk_c%*&r&y`-~S4a47Na zNNo9Tkb%Omn&?N@2P_jW%4yTN1@OxKaTLHFyHVOsN)kNTNiKG%iMUezw#2gxwtEn( z7WR6s1La;XpAkq1HbKtmE9qyG-&U3}8An0zt;6Z}PLG`bLErk$3+n>Nu^AeU2SsZh zQ41DB9!EPOczJ8IqNe7BCL-{w#M19P-TGatuPL17b@ab4PSQ2$!OTrO6YxC67QaFaIAf8i1!?z!a$og_>j8DRcw6IPE8v1VZs84oyz3iE z9P?C%XQe(_2-&rHNpgW3KLJXTmG79Taw~87qkAU_P7FP)`!KD-tDKvRpb+V;q>TRS zesFlZF=}{KOZ);qypDv(*B_`9QuGhL_R>#LM6+&Q!_*CH_E|}9%Q+rTA!y!Zthy-Y zzKwI*`^Mgv@H08bEka2QYm&LsdHs|$m-P;m#C3pZE?48pc~sq9d~ee&tNZ5zix#e! zYE3@t6-i$rBc`m6hjlWdr{NJL6@iIyAjS8wU7QJ6Q9VBjbdYQMc#4H4Dn zr;k)`T8vdw*P#$qybbmNWkW(MAUTp~8u5trwKDZpWlMy&qdZ=eb~==T)|^ae9l*cM zLp-L`q+7uA*JT=bK_$AQA`qgooR_`SC}9%@M^xI6UYl!=;Jzt~n6n?cbhwq{|H^|t zcN+ddmc(Nqn_oosfyp)G+DPjex79h9d|CnNKY_pfGvs9WAVgAmFT5=15hbZIofo*L z9EY0$ckJmF^T%r!^w?RCvJb@EYi4Gz%bY)mChb4ct1XB~NcQDbC?Xy7f1Z8=&zh%8 zo?LUEi%|oG1eWXvFnM?{kgx##mct`8=I{xvwCvx_nd6lAD*SI!k_0^k+OT5;f4^mD zO~As(K_|8b`s$*qrrICB*?{%G8kqJMYajEkFTXi+H8<*61F`?VA$X6nz9U8#Un}1& z5By~^X?cI|*6rKh+%Ekq=GfFqDEeRW;lEeEY|b(~{^!3016rRRx{s&+TlnDnh9t6} zzc;r)7s3j(T`c+0kexWM2|oM!g(q!SR^r`x-yN)(KBh9Px$t5sbrCxrYG|%0Xsx*K zccDX5+rx;x{Q&a09JBAq2RUgf|B?FYf484;|1&o{V1)bC9@C@DMf1+f$CBzhpg$Jx zST_NU-1<*Ud;7b8Zv5u>$g=}ZVtVz{khzd+T`wRckN9q1IW~U+O*Y*4WUKu1O#h)z zUwKC8f``A)TtDXx2#Xh$<(F75zOc>`hdX9!ZU>J1(tr+bvGyrfus7evBjb4Q&_dDylV5n0|7_5MUj$I;$vCHV&t&>E5K;Xz8{_F&(E zdBZ=o&q&oi!`6|IR^Vy6ye0xxGPj)i=KhNNZ-(v{FbRvFJ>1o)1{?=O9qc1`&#G5F z-&|0%eQx55(iP`U#6d(9b)PwUoloIc^7Vk0x_4l)wE0jP=FN;u5p4!hdw_s^s>fn_0Ka;$)tr?xmYW7j~wg^Ul%`@uHNQ% zYBqV|SS@o~PTa(V@9O7`U;H`|uZE~pYrsqJGhwj|@?GK?VC2;uB+(#IG^SZMrrC%PH)5JC9i+5j;(9A7A6rsv zEpNvtU%Jsx@#wrk`d2*q2|JmNQXnf}vcZYaP2c+-L}cncEDdc2c0;`U*a)$MxPDBN zHca|NN7{;z6H%hvPR<9>(YSb}oK3>5@MH(=8;st9QCl%8W~FsIs47q~aGlnxW{x}P z^2b@Z_N?=n2lqsHCnI1U<_<89))OSkQs2C&jMBm1#==|-jdDNDaXi%eqLd5m^KU3xE;w$lOUf9`tDvpgICae!R3rhV`*ZKgD!!;8sAcB16X zcH)i9+Sd)F&B|KmByj_eEaK6c)TPekqFPX4LTUQt)!ir^9|l$>=eo}A_t+yoxiyG= zskg(!2ZJ`2krQ;Jxs=+4+@m*GM?=@vW?4zA)zPQLMVG`ScU#M$+)`)w;S(5r0Y1$1 zumh&UedU`v-?n(aGZ0A$=E*d~PACc^MYPr4WRbU7VFFe$bBAfO!oAp{CX8Z|6`f{P z>_{o$Q7XD*v{OoeJKR@Ysay4+ULmNV1VcC*@<$?t%F1oJN)h|Z1@A@M9IylhkyxTa zP4wh>Tt$lMC5K~TWE{NF`2JKKEGA{5l?s$m ziP9ETo;)F=4G5}D!&DOnq7jCi4JgC3SI#d7cL16dq)ClwR}JBv5QWG56mt*#$$w3= z`=@O18{DECq;*zezKrtEa(c6!@^_<7Po?*Y z=@;0v8ui(p4oWRzxSLt`6*wE#0T}A`bdeEsK=AC!fDR}?R&)1J>St5#x2`nq5_n8n ziD`Cnmbm`Y8?l_dBRj}nraG4T9lu(`yc*>x=={bH@0I5$6x_($z(gvNb%}!~<=sh^vIGb^< zw&UdA)YhiGw088swyBmgD7_Z}G{?SqRh^6u2tuKkGoZFCn%j+r z&IVb-w9x=Y7e@ISz>Zwn2^oF$O>);TrS4c4Zs2 o7PL+lTTd=JuqEre=-9@(we(^%x#wk~zr%yv0miC2AqcGeUlHWmnE(I) literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cg-t.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cg-t.gif new file mode 100644 index 0000000000000000000000000000000000000000..91f74243e47624387475f8cbce7b5b5121818c39 GIT binary patch literal 4805 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 GZTlaPQ)Mdv literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cght.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek/geek-cght.gif new file mode 100644 index 0000000000000000000000000000000000000000..4e1299258cda297c85fb24c9aceeec1064e46815 GIT binary patch literal 4997 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/green.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/green.gif new file mode 100644 index 0000000000000000000000000000000000000000..4fc0ba2f5459d82e5f3dca106833596c39a00813 GIT binary patch literal 12455 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�t z?v@RUzPPl$Bem9>#rAazpc#QaiIP(Opw^HU2X`E*h=KVDu#*jNc}IVEW2qLh#}40v zjk1jQDCjN{Oy+k`ISClDf#qpI6yTuQEq;kaSj7^ei@;vA?~L@IOIarvtqpp5_l*H!-U%Nco64YZ9E)80v99jLx95fe;9%VvW)m=0i9(pz)P5Dr_`KRJp?8n7z(Snbe zft7!dNHZFQ`~XImgVxaWI##7#OtgobKPN?_nY&2s=t znspZi?68mixLasNhx_9ZdpHMaDVJfH=`KnF4-qZq?qw1S?qZ%mu8D!bEciyuP$FlWvUjo0HSV>keC6%W`XVvMb31ImE8#QxJa(d?EWItBd)(l<&4y<%bi zwS7yXUd*s8-bGj7S!fWWh`yL(IUHH{@KA*aCSv~xpuQWvRU%csqo98hC%pt8=jpuS zb;H(f!kQVEC|4Pmf|rDEGDb-zQaAg-s>G<12sD`3&$R+IV={g~^vo!(?j#@qU!-`m zxRnX9BmvLjSIkI2ODZY}&t8H9exN~GSuROLcqa~6f=9&D;g&=w`wGO51_C?u4`(tK zj~D!LY+}N%+anV~sjyJI!GboUw;DZ60^XplWGz8|GO$y(&`NkPRRQykN=r1NeZD{X zhy__PLtz7OXYe$T0<;D{cAe0;N*W`PKq*3C@73YtUSzfT2(|@z`7szoK|%O)SId@< z8Q67&#UGHqA`;;%2`=ymJ-(0T%Z8n&!n*b`MTGvWtFTv0gc?3C5f2KXK^EMx+;06! z1RF6XMC#MTWe@w4S33REv5cZyt#m?v2y+3R$*?E(ix;$=ignE;xtJxj-_U)dUN-d( zptrY=seQaWgL+)la_JbqqO^~UxJvB)3^3S7x?jSYu>jmM+hNwbxdt{Je|2-LmcRel zvZCyKRX{ca^k7Y|gPtPlWRcC{20cdoRz&RX1}Ga3FTg{{6!Z?uC7T7er4(hb4+Imp zM(KboDxzB!{KxRs-afLq<(4uTRpcb$ zWETF6rperJiGsarS?-qIJSKcm*I|ee*{C#BS#LYnRbcz3RhV^uD}!mtfQ(aN<1H|* zSo9@r;*cfiVZk!v%h$-OlQV)VUoQ3Ejdfj>ftyjb_gL)jn9#TOudFD~o4&B?+q6c= zu6&o-4u3H9HgU@1E8t2F!VJGnl3!7`de!oLuRCk1;EifCldYLx)98V9Uk7~rvYYlE zGP;iuJ;BUy9W5Rssg#TBtRva4fOohjub99@!sXsi03I4>0;6}42@l-|>Ed8g|KofE zlf?vHCcx73KO$)$AoXaJ0m&jBs83=4%>MlNg+1t=Y2W^39wus-hB`S>_%Q5-U8KN7 z-O>I;w#7-T0R_Ep3HmCkQDCrdM?tOYIVC*#@QetCk=TCik2C-Q963m7CeplVqr8xE z?o5o~$cEj*2KeO$z>`2{D8I|@(ir*5t#|vU(Ckg$mUkcmPrRaM?nFE&D>RH->tI(z z;$l}m_Zu?sv>@A8A)y3ko2`bVpQIR3TN`7YQy8I4QAIimaZSndo7PzNsv?`!ZmY%X zVJpttT4rJz^NEQiDV7}Fo}*75nLffCsp|hppK?Amy3m)axG|^BzwV)tB(+|Y3AO+9 z-=|Be(uQm(ztrBKr)ln8&8KoHOGD@0Hj+!8$DB)eZ`0i@p?N}!cr=rOz4@^$;9`H~QUA&HuT#+(t^qnx|Ob5Dowvp!1vjKdPSM=I2J(%EW^UTS zG`3YQKhO|dKDC%9wUj5J*rg(GdE-bJ^h$*1L{fcHb0bcf$`7J#7eBald)ue$SSI?d z#{0T;-s+O3gmwO-znnO*3@af^F4nZ1qn=al8r*54d!O&#)5Og}{yfw8hx~rDi53md zy6r;k=h6P_mEe8SJ7e9Lk$4a7*e{t}Pc1{>5TQf4B>aY3iM12;G-y#ICitQb+2n8@ zz*S#Ropr(dWqiWILY^1D|I42?3|Eqxg3H3Shqqp7-WyUjre9G!_##pS2)&FtiPYvz z?-XK#ek3G@I*w_<`tYAwwFX^ zlQ$96rDO>eKH&_qvLs#e;y#-MTp!y-?T0n0ob#>|1-Q3y>G8ok?)lhQN*4Q}vr?WY?T<9NKjy_>=lFchi@ps1p%3+|De$j66PCePj4b%`38%0dcJf} zbKY}WUMNb?zf=a!W6mx|1we4nej#lITW`Kfj<aD#y2JC429yyTb-qOFprcxsJurT)$L?#^ zYzMG&Py0E34N!Xs;7kfc>XN{2=|41Vev(Bq6%#aQ--|>YKFPBQQU}Kk`nYw!WIVg8 zdotFvP^_FN|V#R0Njg%y*29KYo3rm^D z@8mU6IY?cRD&WV*$`iNzTxeob7BGRF`j&4dI$1eOD#wj<*gZiugwryY!#=P8%k*#B7=;{= zV03?wOgtBn_>fck1H7pzKq|2u%yB)3&zE3 z|FP}WF!=lxM(A(#t%aPft9T5BsO0`$2QOS;THYI_cgE_Sx{K*O^u&75sdCivNy zKJ_sT0gJOuBCjqz*t@@z367pzXB#|yA%A;63rt=Igcl|C>{xA%2UeDHmJX_JwI%~% z2j3(DA^|mjlU~LDUae@tYs+Y5tY!7t@;(0AEy3%@ z2C*o&z`_bV=g*mIONR~JqKQBOA^1hnd-|+JmL{Vs+p2C;D{2wGhJqHh*UAR%-;n8V z15#5W|4FEe52^ZcI*D5b{6V6 z`-4lw(-M#9rADX2g~;BB8}nW49p&tI*YRs-pZ&!KQvlJF`=v`QaqRPPkvbpOIGz3t zoa3@ZseWAJPa!gR@;TUIj?VI)C+Z80(Bs{P^!d}(4HcO!P)sd>pNt=6m!N{k;&Ts?||y2V3-sXTj{u%Rctd07IpTH3q+yMB`#*ZURV z38FZd=a{@T6{e*Q`Cn?P?1a^MUDwmov#`Je2KTrf!LE`|08PrB<1YP0Z<39I5-a}< zNSW%c{)ywFbgXpBy$oW2$pFm+f=uH7>a4-WPnux+{tFQd?qGeyah$Xpp-~H<`>Y4dp?1WmCZh3W*4^t`VzGmC7c>>|1)%#nU?=?Zbc(Ms!!Y zy@oV>f~hz%AjS#gpJ*Hd2YLllyOjG)O0Ym4+E(BNJJsyugN*imxyKxD)~wp&M=^Idg?7bQOieP%WM?JfK}jDsRZ#K{&V5fi+IBgW+61t(1j zim@`8>e4>`(skSzZ`^J_fm4`-F=1dpOLs|Dq>tqlM$YAMRgo&GGib0i4rI+VQK!Pf z)FGIKBz&rtbXd0X7$7|0-bv!DR1c~JkdP8IWUPaJNv=wPEr3rMYVzd1)SWfubTjv+ zp5=9$Sgo?)PGnrGn!?f9Vidre+LKA*(?POc2GC%0iRc<{k0Q%@-zXd;LQ$WC~2~)qlZkhj=|ZW zb!McTK&}&YBM~#*f2hiIp5uzT;uuxOAgwbSi8f3yxrl1OO!E4egl8ogvyyhtgT$=j z+{uYL>Q?7cPiE$Wr@7pxrOV)387_xu819wSev-!3iKi>m%4PAe{Un_QuoOA*dh86pn8K)i_m4!IPcAk! zmg6Sk{l1h}yC9?A!S-%i_Db&NJ)g!5Kbspu=f3q;8t+53+^7Ak-fT|3h6vj@O}*B( znp+l{gZxZ#xjOYTV&Kc0OBIuENK==1R~@{rPDba~X&^89vJZ^+PAX8rXV~oyq+fR? z#GUP&Kedr`mIeK<9>^Ct!v!~o7!jfSP>I^Ya0en+fl;QrXh7UW$4KJnoPR&OQ{4*a@ zuElED2}_c}k_yWgoaTk+Eb(&*0Stiq{-|QAmd8=T+1j^fCHwz%Kf#hATvJK6KjS!n z9A6a{{*?9)?$DGMz%RtIYN}k^Cg3BtvN_C7*IK!Zh|lWa_`tW8-2Tg^BJN^#+)iGJ zkGqN3n%?B>-dY&d=xJ ze;px4wpWe{(X?!L+LicODGvo|x_O*Vt!=w(QZzOGA2$ggmvn)ibRjzNLZ`{u#w3>( zSWqqS&R&v$!fRv3vUb}-LXDo!zzy1-uT_`;~$SltOqc@s7a=Z239(%B|BrZ7({c99?q5$3)C za{mY=^DP6iQ!I}*EOEZJ7+*WNB#<#nIBDL63KJ`W1^qAdEpj~<`P!>C4gs6Oe}pQ3 z^!#jv_zeAEUa74aa^&&Q_ZKsFses^Mbg%p7h__YEe&EUGM?O?{!ceIi~)9Y{RA`A{M- z@YhaYT~0e^puI86WItgdF`+g&IUssdpG9qWm(+NA%D5J2_&hELV{Yj20a8}*=~Oc) z$q6c%EO$|}>Dz~_PGE+wUl&hM>*-IeJRCjq-s!?uzHr|S7k0sJhq9vbN&%(FUXP=K0+=Ig{#M_Fk2)9+mMCm8SZpkR+f7D@l==WPoSWVI?Y% z!L|o+zmGO#_IFwfp!YR_d(&S&HO)M{97r@?K8}H$NrX+u`ijw(8&4;QeopeDik97hKZ&zuUOHO|^*}m}al!dTg%&iU%bm+`PlKqt>d!ZESJan0@3Kcsza|~H@l3H>8%eY(gCtO zt?JV~Hmf7qHT!)}7NhP=_2y!)8_jIXn9Q`B*mh{jy8)s1;JEH8kp7iRd#KOHy-S3~A-EM>P$N&xtwk z`%c*vWZ6FXGrY3ceQjyD)P>JzwmD*;#@F)Xy5;c*FOecU-|hdZ>s)O2m8q!G{^D1n zZqo6ngYT>_B$pZ%I+Z0*3v_1y&@Hg~Ca5|&1aDu~&iSX}OPIp@-)gvoP5+b47l~Vr zCm(IDN4@_NsOWp+%r$aS^0PA7>Radvb_z}N_cnd~FE%!6#c7%?CjDIhOVqGH;vFN0 zFdH^`>&By(dGQ)g^?SchNF2vXLg3y2-D8m>Ho{#!TA|kSC{PjA&dv@jsV_@utllLV*5+qWmZ-nmIw zX`a~~Zfk4F=EbJBnB*KEZ7$2m=OU6Z|GjIg=1cJkxQW0H0I#~hgra^T&$>lZJ}_?n z-J;*?jKFlK1LbR^JEJgbePHaD5^%DY>vQnG=TPmG!w^98e6k8g1bo^yl zIzO^hct3U##zhR?c^Q0J_w0gbD}u+VGENv+R26TlDOFvl``eT+0~WPYQ5qv~zB1>s zd0=hbMHi_`r|k2tk19saFV{T|>#nbTyldX@*y-|4%9)zq{ZcJ2q6DN{2EA@TD%yZI z6VFVYUrugl_griYzN%vJS(F&@DeYCFVE+#e4CO$ zvHMAAeGf*>T=+Ao{PIsz=C{Jb`jz&%v&wi3!e3Ab6;QDG|Ns90005Mfl)b&ZSEALl)$J@&ZAyu?wAJh^Qf#B6 zqZ=C=2nYx!7BOREV?shgAt51ib91e&t=`_=00960{{a60{}~x@&&U5}X3R4)W|^7) zfPnwZ%>VH4@ZPM0#?|7BnYC0@{e&MY_A^MRsQpw#eXVp;R8;=?)1p*V{2mrbQ&anS zZ_ZOw`PkF%Q&ajzSiV(N|2;G%e0=_9L{L&v_};3M{QUg$=HdJM`_(Z-Qd0N7zyA6| zSdo(aEC2ui02=@x000L5K#6cjEEWOCBtQabI-gKyK$&Dl1z2o!N?k&;MZuFxwK@ex z;kfI4qSNcHxruhz?P@7|4iVTVfOv6bUk(#P6Ap7^N_>8Ykcxwi5mA@dU8;trly;pOQKJl0-UgXO{Kc8sb#WGx~`~AjG0lVyu^E=55TRq$fsrj z5Uc~WuLBeh6y4n10inde$PfeH+Y|uX;Zm2t>E8h0;t-;hl>HwU@@-)=kRcDoOBXJH%a16{y`1?H Xm&K4!ih+9fPUi;_nm~j43<3ZnGb2Xhyeo{6qs?{6c&vD0V1S$BjW^CD<3F?Gx&!f}$==ETf6TjiTaL41XC|-I z-#@%uF96O{p7W!kL;&V55q9VCH(|eX1(VR?< zu)|hF;FIxCI}{)g3+S%MSsADst;-RQ)^U>qSDG^y>XO@&?FKUKn&a?XZt@+jLo)7v_WB2W=z zBnk=O<^*O&phmmd&0I1T1*pg|4)ivTi@@9Ap%vVSoJ?|D1oX#`&jSP9qoV`O&2^)r z-2(&7IXTG{6`AerIVcn|E{+@#frUZ=NF;#GjUapD@pf3OG187~O!l_(4kR1nu{rEa zJ2JkxyAEZH{2~4^F*`B4FuSm_Ffcm6t>D%**Jb8p=CE@rnk(Wm*9jOHPi6i)$Vjh|A2Z zXm95>Hz%{%aXC3CEH;kIMWRqpB(iQ>-|RxfwyKJ{%9n%hU)yS?#t%{goU0ARMg0RN8# zB2)~hbkb-wtLb7rDswXJ#f1|R;4t$#BfgF+N6x~$e@y=M=&Ab$NNpiSp<^X_UegUB z83{gFU1{xgHx*RP!)%hU@{$sJ=aMZ*#AxnuT4Z-_&_o_<zOoe6|9|5UyF zW!?D*AHKvq7uiDP-C-!E-mf??(>zw}|L}hQrI2Rgy+VniuUEd^Nf`N_5c$0={OZf= zcg1UcStsVZk3IfkReSEAqwl5|-kI+I{ueiVTG3`%?v3L*4bKr}jgQuNpr;5j z45Yo$+v@nLpO0)~8!o-IO+5ds(7b2-XsK6y@s095HVBoM0qh;!l_9tT%8A@W;L&qg z?1|RU^1W+rp%D&8_s2&&%!WK@aJ@Qmu51ssW>4ALOFe{jzHvn}MLYcx*ULjb@$D5p zLEQV+_VvtxWKd71v21(a^Y_VDJ294OUYW;jALs8Rp9#v-|I}0$%s6o53C(BE&U4+b zIx3frUwHj2$v5la%=BfedcA`_bz09A4zl@wdrmR9EyyCnZ*FN=ab$qST+Q+PeK7QY9YagL=>Z;yap*e)G!^e!@*54GrjQ+wmuk^xdmO~ZnsH}bT;Pr~e)>J7xWDUM&S zU()TMsE<)+3cONckF=MMm_-bk`?x*SL(AX0%&F99AhqVmfR?J$vUmi89i*58Beq8M zg*H8SAdwXzWy5fmqsG7!cnrAtMlPX*B!27?M_S3s$EmrxGZ>jd4Ujfl zkdID`k@6SS%TAO)OlL3>c9TGPH0o{%usu$J8)xEgOp0t(NK_A&Hsig%9`0Ra$LCN? zj@A_J&VGI7d@I|~90>Dt)sd@0vN3uwFsc;;QI^)CXH{Qd?WuFtp@gmSizngLHi)Fe zyXuXq!FJ(>kVTWOcGyLj`-ukm;w@LLu&DyST}=vny3PzcE-z zwKS}BMhQ!|VKP@|d=P564$^I32V>$%$dpNjBohfiw=p1O3`vEbCS_{-L@E?OQ6QIq z6nbgMnzT3rqDq(2`-Voj@!etCiQeIal{RYqh>72ZkFOqCv5yPU>lJZ)08C_lHhYh_ z#Dxd|!Rf6+{r}db1d^}i*-k0GhtxUb>3S$fKZT|}m22k-RM^X7s2SMgIieciMM#Kg z70usI5UX&#ZrIG8bgQdZMfENn9{=Bx8c=-cb^S~5`R@n!_u+b8_jo(RPM2IPeAUA5 z?MT+ucl$#bY|jywbELa!dyQ|aLB=0$&An1L?pvz0#)ZS_$)GR0vmj6ny) z&~NCxS<1`M$QQ;>tK4V@6!V9M2d(ggG3Co))HQ>%eI_nOjhD9$RJ?*joxUI2D0B+a zc>FzT9&0Xx*7X8JaC<@jEUL12}?&>{&EYT!FmC zS~!y4hqnr|onE9qx_|pG%A>D+^l550@#dE^rhl3X_wERf0p?tloS{k@Sm{7(W|=C7 zPekghE!H}U3H_Cj)bvRWlzW3Z3*0Jq?>7z;T(7PlUy@aU`QF>wIk92*qKqb`w z&hAScd7ZX$?cbjV?sa?9O%z0I{Z$hDY71DiMU;8r$MLC*v~KLNG>|D^Q97rG32&QZ z#e)~&wuu4=oX5nWbU?DuK?zR)6H_9R4zs23I*1_oUB`AUt-9M!Phi3iGodH%46350 z91z(c*%yF^wlj;enJIDFYSnbz0bFjR__%cD>d>`D5eKnF(pVci=`bBogkv)#8CFAL z=?3D-Rv#=pJIYnZmc+6jtA|>)GL#jjF8SP?)#p>)p9||EpFeo7JrHZU-VzVtWW5GN zvqV`3L?Ds?qDKVb@+Cr!NZ6!F>?)B+pdSdMLbE0rY|(D|x83FYB|HG0Gz{2DAc3cP zx{0FQ(?HI2P}t;N7R}((BqH_ozwl1T&NK)fCjq=6Vak`#5S=jT0Y=jx)&PhlF6DVh zkfRhEb2K(+E4lw@uG?000N@B+NpdGK!Zi(SMFb}b$d~CBim`e>Zm3B0*!C+s-m#8) z)xtVrNIzidoEC>W-fH9X)*>aC=!%1-@af4&$WCJLt`g2J8nlSx5hoUK@&w^=G|5t$ z+MFk)sQ=grXImg|fVIXRZ2QAt3(45IJ#RubX zz#!BAhA?&O5+!M{%rsbj8ngr_d4LAB0>F-2da{+l{{o=@K0bW%o75SM%pV0=m}GHm zC&UveSpo=aUp>Ii3L>n7ZHOSH$r4!+Ko$l>QbGDi5c{oH2o7B6kuto`(|r=`1mMP$ zNLH+4uJWUZVCwo1_5exdzwCtmZ)HbN&aWHu-={g-ijNhqPZsx;vEZH30l2VCoD`>d zcfQ0w%c>HY>rzKBo>2l=0!4PFQ3*I#uF`pkfaW%yG|-2Cxfz63uMb`0i--ZU`gIbIc}gFCCI3%GgJT#L+(5?RL%8HVm0N{EtQo4l-|49SXugg3xK}hk>)l&htsepQZr34Kz zur8BEgbM)hUj>LAK$!(r7wRg6lCduZpXF2eT&AFT9UbE$0AX)yV zQ|(WSBNq)~r)8b*VZPH4dJzo~H*2Gh)%8&UACQRK0K^nku8~)J8!5X+0{}!a!V<&) zuXeHoF^G}oOv-#LkvoZ$zAciOuc;eIYv@lxJftIjh|Uk-;GY2SRW<2>68K6%-JV;u zeQA|oKpUz#wj4mc(4KjjUaoQ4<3n$1_OxA-ui@_XI$9L^)@7C9R_@qd7;aAN%z?v_B z9i+mqq`~V8vc!DEGTq?wx{S}Qw&M3P^?Vr+67U;$U>%4OJ2itK0*do@NU1>9oXufp0R)PqS zE6CT*&mY!FVp3IoAg$FkP(O^1(UK} zX>cJCK0gU>5XeN_lnE$-tWiV!z>JvT8o9#6_P;Vw*;zzt}Z zp0D!(0+~4+Ur^XqRof4s_Kv^khv@)DF7@A2Z`rHfvL=#Dr-7pQ(K%jH{FZ2@SQYA% zDD{&D`Xz!3MVDhDZbFFC!@nxm08&=R;jeGXm{9r6RO!AV=oC^a`9pK1>A+Zlc0mj( zybM)2Xe}KheKA~xRTSRYD^3& zP)8reK>4SrQ5}(gHsI3~YDKBqFxh;9AR~3(3bm67Ef*Cl(2#0cayLAp@@)8=(1A+*wALR{U$^{mW_V#xQ@bJWY~8)= z4%Lb_?%^r()hVOtC?ls>MPDl346SY50UnR<1ArI=O zKf07|h9`}Z|p4 z*e#B3Y#Z#4q5p*3_m>1%=R1ekMj5btec zdHQu&A_lMA2=PWrdZa;p!(Bp&P`a+|vT~*^4&pCfmkhFr+K(creKk|+(oq^htFTAM z@tP%?DxHvL*V)P^KC1Q-pLY-)+B3_jGnB@+4(9;U4qqkP!3!C?%Y@3JvozQ_zHRc# zb2)-Tn{NJrx<{y8FD5eGZl?}LepKr$eZ|+wPg&zFO&$b%iMmd7{*06{arP)E@!;a{ zyCy+aQc%bB-OXd*f8GZBeFKMMKu%Urg)2&q%t=N`8Y#R|$6QGpESDrKP5= zuxM|yoMAkoZxx+*?SzjYEVL_uFRv6C>SPC&)TE51bPhsdnE-ssV{jn4MN9Bc|T)nJu3{Mg00ge z!-)`AKGB!HKg{}op9mBWfSh;>CelIrG=@$InY846ad|oDl=s!IR;^9mEpeee6?RnM zCq5P47cbp{+*MK{eI5WiErJ$OcMmJUj?#8<`BK%i&)>~IXJI7wV{EGhj6Lg6Hg27b zk+jN!GOSOtk#nUbJ4-Qsa;N>c0_a%*te6U`rwB7xa>)~=OlQcxdKmw=I|s3C=eY1J-h_Gn<(j)CFLQi3J@flPVS-Mj#suw zBC0`Q;=S|YCa^uy+qDFiii`NIBRgGkbgYp~{0fntk%|{E{FI@^ccP2m{4nWBzO52# z)FZwHMHVWhmORe&E7fs-Pshf;kyW$IfiEKU5~q1yuJ)-PD~um&cwdblWV#hCdzBk{ z{TKIa`i)PuMdaUP>+8+FXRYIAQ{LQvVjFTf{$YypjG_KHyU60W`@!>%A+Htm08-Zu zFlCdzHhBe&PLx{2(z#ATL!TO7*Z3Kj630VX+j!@)j*>BJ|Ixy>9#`D9;vu!t0 z0<2zO#Ha1)0`@21+le#eoU6E)>9O3RLgw@?^7W+0Wqz)CP`eAxx1MRKt}j%7 zZ!eTKJy3!pL;u+l!I8LLELa&j2mnD%CS#!TQDaOldJfaje|L1zKyy8|senVO%hoOT zTS(M_d&-u+mho>TGNnySHVolH&2~t7yKH*RHgV>!g9E+VL0mb3?Q6KkuS^cop&AN;L zY;7`NFfTf_S8&SW)N1`H#pBn9KuYW}2Iq5xos<@-@$W@Nr)pbr9;$((lZR5WB{7Wj zN@%$VODW+7v$`dT5F~niZ z%hBEuo6CAl3-ltIj+k9q4<;QBD2h?PJC**vQ4U?^V^eecr%~}$MS007B3OQoMnO0+ zdtQLc~zxSo%gfdf@hDs~>;<`)#MH`KBfIHAKNY3WU7z z;2}V2E8k^2M)q_ySkBg(*nDg#_9f2aPneGE@o}L#Ktz*jPZt;O#emW6W5cK+j3k+z zC)-k^waG=Y3_|LOfv-u7!V>j&%4{oW_(P?uQj)&8SoteC;Ce!OZ+P|TSmf`=OJ-ZH zV@}>^1DWX6l(W84F|zH)TvdBSoOjC0@~1gu)jcuztdga;Y45xC zZ83bdGCj8J3Ly&QI_ z{!n3$fw89mP;4f!$P3`6^pXIr9E!8|piB@zsCIA6-SHEi{tp_X^{h3QfZlz(y#Ek- zJ2wF{gaMJofj$%3*0RL{8PY>9p_HLN6i2H9HX*hFMw0`8|SA>A72NT^>f^v zwic!KAR9HI>$-qnc9YSf4uHl;oCUAGmOIcjSN2t4X_I=Vm z8cXXt1YjjOSp=jtqFUy1Eqdgot{&CZ_zj?2&y{im()fTmqg;pU>C(z+NOd6!AhmIc zN&TvWl2tY$A#&z=ZkMYr&gEIECl`?e%*8F`M_Q=C_&c5m<%>qF;D7S$?bEpw_2q1j zG1sb_CM`CHLyXnl{YOIB-F8JU6H}!A!sstzyS17`ZZ_`+pPVOjx4#gK8s(VK0}a5k zw*jM8sAuq$b*8Ft%zf{R=ZGXF8}wS3l+??!h@4+T8VA>NEmrT1J#RU~)6mS@*%KfW zKCF7Oq8k-Jmo6tugg6^oKJ&d48}wh#tj34xeSbyr4=36|DqB|!_KO4V9)<26C_WMI z224A3ENqVTWef+XE-gMWcO5W7iwE|X7WWr|G#UU+R;yU*mmUfL)b5@>V9HJ5DwM8_ zNt%Jv?%$H_0yK?z>@iH4OJcLsZ;5$_$_Kx6G*^GW4%DjIf91rR29qWAA2`0%U@72} zR`_`D4!Ut?jI{FllGY2p2cZzlO@*^i4W1XJPptzDD@8IbM!6Q!FG!&ESgo(fJgd3F z$W+wyxdkWy{wER9{fnu35s;@ndg7hCefZ;m!*ZhnSa6H$PbZ(6d+0S_$gUef!pom% zR?qQ;0b5}0yRB}7gFvu(>j$sYBpFRm09bcxP)>4n#OPDN>7#W+sQ%VfqmzrCz+vpz z$21QUljn%6@m|2~xm@kM!BdPqR!{O@cD1ZT9?ZghJJqU{b)3=xG)F;f?kai?^wA*N z0EXPLEmstDL&|2feTQ{aiMaf@uM|Z7(GIxIu>P`$6V$K6zu1~=BuSH_0gg6aF=%dn z@pAiOw4^qjJ!)2-o>6MJq;{WplMr=vGrqU(jp>=24^Csh)S51#OkGAFCLPSIdm5$I zjX7?S^Ydb(MV#90`NtQi-bD!?jo*(^(L2&Q;3El|s=YjWLjT0K_Co_7#;QlmTK62i zZYaAJ|HJ;p)SjcAjhgA{|K`jo-uTv;uldiLrJStEECrf-ibKfhYEk=D&EYG{{zdy8 zcT@yyjsBiqFV^*X(hc6KSpVlks5ocN>2y)43;4|h=B5?RJY(vD<6Bezyho98hZ8ta ztM=D!PUYC;)H~dMn-e%XeM7vo`HJ$-M)3YWPm)L{+A}rPLdA|xAAUNqa?$D2!HYT1 z+qM7R$oaeW!o$J*mfWt}LY?%S&nL1#+S!{I4i#{A*NG6Xwnle;I#ZPIxHz@a`)T~n z=22Dg?9~3iB#aY4?`Ax10K~SdOwOMva(b3?^Vx5^noP%QkDU_6?BhANS{sQ8Va|7J z?IWvmmojf9tlPiJ>~~3WSaNWd>9UuNckX04_p%(;mTsdeZhySutl^p`7uEMs*!S>@ zW0_~e1lV!>i{pe$zcBgE>koYegD!W|?--QzyL9w_O(*|})Tt!i(cg5@9+o(OaoP{1 zfY3KVyKc?|+0`Z6@pAHN`<%pAY9%5$64BL^-PII(v{dvK%wa|%eKL3JImM+S*ZwOd z(r9=KL~4t>)kBfY=GlJ+lUig*Uff&!xZC{9VO1rEH?__mUO2BLJ6s35z5C*f>UR(a z^*Kb^^dbg9#CL+FG>8$aVeY{8m_H2I5A}CIuZnTi82xZ&_qzM)0E{v zWu)Mlu6+$fGJG;O({g7B)HRYbnm7ZCHgffxcM`og1)q2H=yDDGW8afAeD#a-TF_np z;JYijZrZ!*_NLsye(Y~sa*UYoH}KXT)b0Oz$)2|9#)!W&)aW+4H1cIp*6@!*p3-Re z))3H)QXY77I__rqgPY>I7fx5MOC;5eX4JxYXN4|Zxo?CLqTlX{bwh(MWOqUOeCkMQ ze{QL>J#PIb9Y;HcK<*rizkUC=!yVlrvtcs3jr>FCHXJ$jJ7_EyQo(lh)CsP`S=l8x zj-Ih}l2mf4i8DSUlo5f* z8SeiwXb8Xax6fq&;;0)u^gU-}x1;xkl!iTKj>i2%e<+@jR=b2v{X!-8Fi%Omo_o2E z)4n>VRu(0E-Mgbg`y%~xr_$vKX|)!z&B*n0U7hx?ISRHRwKXuMxj$5FkJ4_BPuJ2>3< z=wlx2xG-aXTZt;{_Zqu?E5vqeDaGD6in>)kF$z&KNO5}lz$v0S zH??APUFp&O`{=0FTnIh?66%~qt+Zhp6Jk^?yH0mpr|V;w)Y`@^9j}Qx%9&q+@)tmIfPqHA9t&dZ`f%yhCyHOE6LrVsXbik63Lxx`R%lF znCx@|U6{=EC=og-! z#gTYe-*OqllnsNp6G09bh%pAD22jBpvAq?*t|3eelC4fEJTvF6>FDa8a@()Y8QnJM z_tBN+t#jVh#e8{4uhU^bacEP1C_H<{G3xX>?rBjvh`P%8G70lqh6HEUs=dzvls@scdCBj8x2?Wi3fuX-(=d!5zzn|$Szht`^f%SVCufi3HTVQhl zTNeW%+cLE=tk9bv=T$J8#!^iKdH2G+=SIo%r0g(@6@BUVB7WeeKF`7Eb_F9E@?vSfng*|}6&ZkL4wuikm zwTD$w?Yu zh-oik+KnOjy$JUlGImfP3-B>Lq`l34wt zSG)3^fpVX2;iC=RJzcdBQd^|Afa{kXaC!`4I0xl&_M8sWG+c+3q)B*Z??HD!cJbL> zo|?_sdqNWA(51PbzZD3LAJ<2soeL)GSrX^KQT2TT(s~Z^FVE)sDir}AJh)VtwF>z2 z4Dw(Etg(Ydpt13ZY(g*C1jsg_BP{?8dY&Lt8Y2o1R!w9*xgF7O`NfY>EM^W-nMnLC#~q9odYXiC|w_R!1)w<0-FWi?*nYQFE_TIYm(pjd|Yu zM&rMymtMZ<|M2Gd@}kxriD1v%-PyVRTWnVv+dqu$zs~lAE_wArsYnQw^VSQHOG=FN zErATTz9l6x4=n(F5I1~v9t!DcoA>r$s;%bQB z*0$`rn;zD@JYw{5!l7qm;l-)2#M491mVVrW-48PmpGW1h-R6G;zENBOf8=B3+3P6Y+ zkP-m6BMpdX4YBwe7O^L$_2hdME$yh5HJDh2q*$$#^dZa`IV-WL1| z)&5S+y_s-2-S&yl3(#^qCc=~Lk1P|D|ANf<&GQ1)nW^jb(|Vl(l@y|B429J8WNup&Rr@0>Pr zK#X~AZkV9ZH!N351UYcz*|ko%snDTMq0ochH!4v$n(zvEApxhj#9RxQ`to z_JYX(mIoDLm(8{Z^qOZw=%$Tsa%>MHkT3JhQVhaA8^Vq|3_cFA>xG1oK<;xa0*>uY z1?TkaU*)_FO9P=vw8#*h9gcZ4&G}e~DgL<^wY@I}7puQOy$iur% zf3@SW#K+6Q4BO)4eOpBr&lFudZ(PkHCZ3hi;^}fYPAHZc6lCoQF5<1|bKaifbKhHE zsNg*on;DT>tM7_?>+OFhv44Txc@Xe>k>kf%t`$L zBDXRcv0y?8$1IUOLSvBMRcU4|#xZ3bv@)PNIA-gZPTn-F*Qfb!SN$?$z z?taqSRWW)=VZ{d63t3+_SS@k)*R@L8!j)Zz2zF}2Ev0Js z&^Ev(6X&gJ7g=E;Rdd3}_0*#`)K{Bnl&?DweTQuVFUs;P;wwJhn_kt|uwiiyN4zQ+ z@bf-r(;*!pqcRymELiyT?~HPaPq?z^->7hXA5duV(tYODk4lxy-b-b(wg4Ow9GW~zTd%q_Pth+CFnZJtCGV*m3K+~s>d#e^rNj7wAt`6aDwYfuTF;V{ zr}2d{zD;*W)l;^zf_Hv$w0q-H(Vw26;hPxXiH+4GK{1Zwc=27OAWpEWl1|Mtw;HT+ zz*{8-WD|u9gJOrZqVHqCsL*-&SR@7a%u{XGHdRpTz-pkpVjzzHLvxhjR=iMH;-aw5p53CodLfi(bq4<(A2 zGDpW~Y_w?`#-q-128oi6XP1zXq!J<->cUTBON8=>3|Xpe21!C0{c}i$0!gpN`0cv) zkZ^us)=S&xW7TU7zr^%h6niWUs+!O7kVNGENy|f7Z&4-W9Q$oYiX3OAR^*LxNfcB} zHrY-8LIuffG!US$FoN1UzD>5w9`e-5S_=@nqiBBw9F_==Nf-y0rE1>BdZeB>Xl ze;_=uI7lh?_3-if_8XU(rW&L_R4EF^xB~5=9dP5EyyKPtq!KoduY(J}!6Z?{W#k~@ z)YfZHEqSxF!RPY5v^8Z$LVaG}-(q2Lh2xJlSm9^iAxXquT!t|D?_8sw!-LkPQw~>X zDR<{AQB%2{^J-II)u^umhV*>3?lFg@t|eJ#s3V4~OK`=Kl>Qw~8k zvtHulEWf6KWa6XJ?>?iU(>+wwE7HX?>0O{KuBD(VZ83Wp3UE8A96XcCOHF!C*AX+j6m z9(@z4^9SG)7<*UjhF>Mg6}CE9@jVc+y@0ViIe4f49Z8l z;4!PA^BQrW_^AR}cq~$9{Vm1-3ra7dcZ{r@3uT!Etj z(zoARVY1l*FlASBOYW_P!XI0Ch{9VWl?omt>p4Tx6US0>R4RD6Jz7x87pi``d$((W z1Sg7-6x#9`36f`t_W~e4Ak~ti7d!}+3-NPD$``7~E<>zs+vKcPYE1M7LDE-93WfaK z1UD-_YHG~YUdVFNT$G8Uu@o2hN>Yo5ReEg=PTC%E8$=i#50*Fiws~Bs$)xfUEL-Z} zE8wXt$L_NS>q}aBWZ298yJAWP09lD`WpS=Syyi_&4j;c63u^NTn%K(-uEi#Ja|ujdYpgJVp1eoo(5tB>uw4SMW$~gJNE4o@hfha=B+n=~Lc}_ZQ!dA9r#}Quo!FJ z;fd8^o;NH7V#q&W$0X=z*;Bp-Ri1ZHdU{wn>+-C$B=&?7sY1@zk0Nqi))vD2ejZso zk72OAsN}>N%(@xp(xt}{_#k3>T5^%3uX*fevR|%Lt|^y0-y&4$OFfWxEng`b2U0lG zYpLokS%7nWEyHeQdEfmi^#ZX14c(Ge4aHjIq%9@NUPT6_7d`!V*Xy>u05B#miXETs z>OjbjgP{ZfBu)fw=@Cd#oxrfV8GK<#r*3hYPsJQi&JX)MElytMT*IuuF?U4iP>Kp~ zB(&#gWCXkB>^|$2Srvuv?bGOUN`6h%GQa+SRVDxC+x@{}PowUkZ;Q)&bkRC0o5!W> za5eW*P}_qc{Jg%Gsl~}*LiN!wN#krF_lkfiA8SjlRv<4ECl^ncXN1)#m6@rSnW7(BkHaB6kv(WND5$s|_#H1b}L#USkbFMdN&&|U zw1a8eZ1cCCs+uPx@$WxsHVJZ-(b_+6uDd%d}+YNO_V<6^Rv+ui*>EVwIMs6&;km^pl4n;X@*GxC(5P*Vn9#L(`vs zW8&jkE@KL>fh=IuOZX5CxW)WaFysgUi|>fY1q^EQeL5t(lO} zFAPTVI&RKCa6^HHgl1MD?-tQg&IOI_OkE!6J7Bklv)kG;N$22~{ZDFV!zoYnFIXh9 z7Og2(Ml6k}bJh?F8VLYQ?!iSx1BpV5Ev7|34e=baxdyU;Q*4%nP#q>7EhKb-jWJ|n zs1T14$iz1EwZ|?hZx<;I7DSeffMLAFbbtsfjf4bSjUeAe0lZniu}na8i!PS&Sgjp|Xb++TkwWNqvel%}@vycP zjpER&W2&&nY=~#Q1+pZ9t+LP9onTqfStfLfg{%l?u4Lui7)Ywj72HR+jM#*MQ=3Lu zFPnfpO@RYVb;`Nh_$06+PEk#>2~AI)ypTTCh~o>T$P@<}#Ti7j>k^uO9I|kw5RgI{ z_Zaiu$ek$^=LoRF3}{37m5o(`!#G&}JOu!!_a#xxw?F{605_%|u%Pdrv1}I%w#nXY z*2*+5S-#)gBvDKO?SiW1mB!xp-iDNm1Uu-xUAYtkimgUHYjOf41VRCOdUR~R58+D0 zWFv^shREuR23wD@^bdfoF+@EDig_y?0HxT}kVIR?+sryC%u~^}LK2OZ$p8-1 zO?owY&&4;nZXNP1{p^_3u_0y`y7S)tJW-*aY*OA~>`pTbcoco`p?C=21~N+nnREA) z#+F%at+-@2a_w7<*-VPLFcTzjoC7-qzqIC4(AE2Ze9Dhf3IIS^JSN22uiAXo&FlfA zqt4l+u+qxF)_hhPdAq&?>tGgk?0a|kyzqz?#SCq5iXg|{LZnPq;dOMQj6#}aFWCkQ zt>=U_^=gi-;Dh&~K)+_E=7iR$1O4~Pw7F!w9!1%kVyy(W*#)+WqHKFFA`j#erD+MJ z8$&~lJeO@MbOB$<*6~8;sB;!Gl;DW{1W3GYAjO2s#MLp4zk+P5Xck)}uDS_sm(WHJ zOrY;?41`6_MS}6Ji=JI`>bla=#7Xa%_i}++y z1v=1^MEr*cOBph$U`nF|MqH4~Jmt!B0}D3O7`d|325jA?W4Z03hc8%X3#C7iaY`)d zj~@;Xfp1nN?|Bnd!b9c)+70-`=T&x4(Y zNm@`Ka$F#Jm;|dBG+7n4C{dz*)z2b`&VR5LG$C#|4rsOQ_Ck{k@culq)i5I(v}4b$ zk6CB0sE+8poT&dE?D>6p&8C9oNW1jnImQAFHm1FNPWlL320M#{1~{^U*)EK0uEm452wO606KKVPOt7Ji;6?>)+uRG@{ z8!=6Pk&L52O3Ne^5+uNQAm5c|Y`4=~8E(rUj*1o<%`)Bs8arOJb`=_9K))2;{5qPp zX8>%~YjJtV0C{c_>2R2LB4?7DjJt>5+4y(is%lLFvZK1gVMa3D6 zGNq`T*}!u;2u4Els~zgs@aVn`^)u;cQz3pPeaCVKVRA_8TKWz%iWYd2u#U(4P})&9 zi#a4sKoQLALUmmTdL9IG45iANK#1BjqY?-rvcY~e{Tzb9zng~p)r`+{CY5d)`Df@x z2HaCFSNc1A?;P6yTg4g8uzOPkbB)cGx+?RP42usL2iEe({zjPkPnl>~Zl7bgG^D&2 zZynX48rPxf|3&>qy2kYmwcXb>AK}rF={pW*Y6>?r^DWW;T54bG!2I4ItT&w8{zdSZ ztg|$Pp@=sPdjO8%IY*^Wf=a*bop&*oS9*~a}%%G$-r8YGizD^k!Sv@ z`;QQCzcoBrYs)lIyk?qUCp3@4w>z(WL=$j+oo1e5)n`b8PW zMV-V8n<0u{gLigTb$3>I1(+sVx#}KvH9f4Xx#^bKwc|%80b*(PHQj&Ui1|eo_ZvsN z&dlR$L-%BMdb_YJTMw(mbtq@0$EfzGMP{ljrTabIu>X+m_irZkb2|2OhoczpxWC6_ zZztA5yy>V**kMM{)85o|`KFiL>3o`SK&mSw=$p%af}vcOvBh=c+PYNTFR2tOGjJ{W zN_WJaO-9oFLr=d&XMHtW>ZGDFTBufp#iQZi7skK4y)PUlcv5ILzN+lb^0{GUbFoAH z)rR%yOxyhLI&nwQhrBgS3ECg-CS~@h%4Qt>7xEs;Czgm38M?LOLGdz;}pmR^=Gp5T< zv#=jWq>dgn1Q)6vEqr99aRINvN++E7qIn08Hq8iG`Jr#Y+AqvOS5@+x z-j$u0FJhfQ?TnMA$8`VwuJ6(59GPL%_uW}$D>>*VF`q!!J{;`u6;H`xX?$U8T(ADJ z$rhhIsEbOvSXC2wINi`HLnbp#8-+h(?WLRT^@wSiy_-;N8?*a=72S(JQ~w_a@Uz*? z?i=RL+^=cmo;3GM(MUqlhNO^@d&=g1H&W=Lx#Uvhk`U6|%B3_a3Du;OOEq0}`R2FZ zA8^j&JkI6)c${-yujeP81n*I-Nywe=NJxuU*kh{yVN-uLb=wD9cZ(haL8<-+Teg_F z^kl995CX(m*1k4RMkO3L6&Iovedb2jF1@enU%#F>VsT<$BI{4Q#*;X&$31F0%Bl;vetsEy7M;0&%D`!J^o6DVx+UoPKNuT|+lu!16Bjc7Q|2mf9v&G#<@8$a zl;tUyBuK|@#qM$X%01ntp!HixZK&oncWfS* zE~?$#Eq3?d>qMqrU&NYe#r|CaYD77j(gvx;gWq$YpAdK@##Pp(I~9*|Mf+EkKb+e!H(l48ZH$EyHXW$ z^89GWCreyThZy@#2Rofp+F$o@rR~_hxY(Ay-wn%bMYPx^> z`;jXb<)6INx%Fia|EkkkvWtY~iOk!yH_?s-p&rMlgZJ#O>sZKgHv{dWYp z7VXwKE7|--J>akIv5TbUC-=5us`cvrpqtRt%bH0M+BKnJs}(h>{;Q3R4dYnZLoBtz zA?*1etbK>IKXzODuwk)&NASSA@|C1RW0t+EJ(E=*f6J}6eo;V%Z&_s`J@>W!R(R4< zuewd5(fZ+DzoPb1@bF&Ei#}-?by^tpoZDi}!!Eq?^q7!NN|>Im*~^j_ZmPbf-#Bh< zw)z{x=9l*9O) zXnV&W?Ops^UH;=n`=3-o_>XmNJT*4HLb{B32s?HfW_Gmh;-_oAPh+k<@*en=hb?Wb{?)Nt8Q$3N>pS?L$ zx?AtodPl9F`{xTQgxby7=Mqz{2?__o+cKQ)f}vhJL#rGlTfd3IO}6|Uh~jat`8!*eO~M3;hfu(xW71KAFiY8Of7xaezWfI^CKkx-WjPo<{B`# zQbOnoPze!KCq$!A#SfGGPb;oJC7RAXb61v_IQ;41g-ok_QDGfmAdU+&DCsuha^zIq zzBkCj-Kvq`oD2i>1x4Efksi}Y6^RMK4Qcr|j8q6^OG+B*>QQxS=I4qW5QDkC!>XhT zW(KO!+`*LwX81=zNrV~X!4Hunokh0;wckiPsx=R|h3+B#u&7hci^v4oN8O`etGs&>GjxomGx4V`)f! zMsYZU1hR^Y;p_m`+k9~67(G)T5hz~1ch)<`Ft4vbf1jEdG2XAU=HmvFIX6zyvxuI^ z_*$P2LMRGsyxV_+iv8qF<#aas zAR?7yFMzn_cSyBoXAEqXsVHb%Phwx1@%ztLX5x5}pRJ##!(eE6g^m5LFO3NOip}A@ zbdR#blFL#9C9QjXz>-&H-ze@FpSp*=CDp_A+;Lj%n&BkGBq&DH%Y5F~cxup_u%NxK zcV&ML^t+<1+ehWF=OE(+GA@ZPW{Dffumo&jUrGn0C#ji9Au1^I&_UEI%1E=|co@!aa+(IPOttU}8k2Jv2L6 znZ|UZ?5f7t)@F1t6(PH@h|XvQ$)j_(eH%wU4F zB-h@mEq%s(&ATmenJ-Rr?wKwXo+!DKFtX(rW-FnL33tBj=}9^rbvB@~T3_>qr_s1W zKv2M~V_Op;hYC#13p74v{V?yf$~)C?JtHe@w@eOY79{T4ZHMj_Wb94=;pv?E>c@f) zCg^I+Mr>;C6-u^^xlK}q!NchJ6G3(ZLsvgNF&^V?TBjxxljo0CH@a=xp{P_UWnTyR zSGWM%j2m1Ecw{d>M-iv_TfBBJe=YTzwsPT#r9>JZqUlrhmUpu4o$9t0r>$HESM>?% znyT9Q1}~K`$74L%>El_;y%Ec!?tv-jAY1SYcD(*#e4@6UdMUMU`!_Du5lEM6qCu5` zMU;yuN}F{0amqb5A|fG8Vvd(--Lz$c*&^N0Qa&lvQuTkbeWD{e@~^du6r{H-=xJk6 zoP~Q+s?^t^*V}C-PaMj+{N+OV@UrjWwY?n*-%dULIcfu1chOF4D|I^KqGOnoKk+$F zhk@BK|LofJ!x4`tifHd_yH||p9eVpxWLg6^3SYl`v6;h5gO^@U-xc~FiY`h?zm0%y zFMkR5cK#-PmI<{P?!u%cfSWJzvv#esalU-8ybnAGfqiv#yJkhfORW^P-_6B+`7egW zzYZxx>|@dyQr3$SJ}M-u+-ESxSIx!OmJGZ*wm%djsc(ay1th8Lx1nyYoelo}YksRg z@Xa>z(}@VYb<1?!sFV>~%9KIc%6=$i$sif6xqed9g{|NFR~wrx2EFZO{&w#~_ajEX zOZ4&NgK3WyXCVpIDR%Sd=hjLw(s&<_vLk z8=)y5;)Z=qodlcM5DoCJjao64Tye=(aTz92--ak>BO%8i4nAHYa=y~HJ-^JuKRA&a zIPl_cn)-~h*5=z24b{3#hU~Y%mF#WvXFu~2IMNp5Qui4r6&$6ARFWl~WC@UvW1Hz( zI3bq^fbi=){MIO|F&IF-=OGg4us#pe4c7W73*&DCiDu#W`%nSA8<(jPlK`SbfK3PB z*{o-)EsKJG~S45d9mQs6eCbrsQgQ9>0&v>K2gGCq5N6qJ+8V+Nd;99=P}os>0B2Rzb2M1H9=8cu~YeGG6A)zVhs5DK8tn+nOM+Dhb$e z5^^QpiY0NMMQ9+SYXST)88rxW0aeI6IsGX%kJkEG2g>`S=OpD8S;q zhzjWfOTwHjgtyso`=i6NhPam%iQ{?>)X`2SGRV#t_%pf+7}vzrG*s| zatFV}n}To+0+jB6byS#W&-_3#GM|g6CgT&h@*{@ZMg9KEba)399>=wLLTwWmAdrjL zCLY`ofKbVZOrBCzcGKS}tc{n^MltqlYYVyrH`GAdqNzw5sHiyXkQx*al?Dh(i$nvE zg$8jJ4Vn$zFQICKo&+TL+s#BC6~M;ld!dmwXapON1>vza=;%^>;SQqefP^X=*u^GT zR}l~tZN+JoAjXncqXuPAojB@X9cG2SFFp1Z-nFiGc3*97#K~MYDdK&r`p~d1S^5Ixrh%S0mg5^wnGD4>_4hMXwi6x>pDaxk{XFU z9cXI?!CHkt9FRZ=rR2UyyxHMNgp>RrKRq8fg)iPn;Pmeu?-s=9y5-XEe#qzv&5JQ; z?Q|r)Vl@qZ(W^Qo1!GDntk6L0#zHErnht%-MLEWK_HGzRd_=d?#qC*k4%7^LDkO%A zauy(UpRS|7!M#o3203TZ_wCfOn`*T}&zRb;?R!R%I8KO^3K)>^WCVO=8SerS4F(9^ zT;r?XaHY?%WE=D+o=dT$>r%w;>tz2G0bv!0*dpVX$@s}1NK`Yn^gOH56^Y{owH4y0Jh+!e%>#R=WIRLh+cYd#s@o&1`si_dm?#;-fsj#=vW>H z;WF#dqXKL<9c4-v>!e}>%i!1Pr~wv~2UH9QAo;)G&Qwv_1O5X*ZC#c@wE_qqE^PFZ zm=E;;yG%6jrCtG(56`7Xe)6XA?*r3|XVtC6!C%yU_RHH;%7P@yjm5p5pHWsxc}FGu zuDJR~mMdn-HKP&`egu|pQ4JRb>EJAu1ht(gmbbygL=&fFQY{QpO5T+W9MkbjXV*Qt z3f!Q>z5B*b)sOEf%O)I*qlNX4(!oEh4ydHO+5rl-&`)V6jC0YU0?{lGQ(!>7$(~|Q zQKMMIFcsZi5xys`!h?nOI}j2@Mug75CRxxD05M61dQwFW5+Z==b=UP^3`2GQt}m-9LPY?g$ORXoPUF0ACu!Tu4Zo7nTg6&Zt*iZNVc`a;$&W@^iIOCYSQOgixaz+ z^wSOh>b`f3{`yV1qhyyaoK)SAHnw(q>!_bzkq3!2vU&DF+7~inl$v#rT2(`aA*>J= zSTpui{0te<&O%ReVZmhBG8dKX>v>dw2&da+QMC?}5tqAf+&UB@_Vx9TW~~?Lasl-d zq1*mmq+{B7qD}6u(UE`6@c&p?>>L*=cklJzM`Cj2^>n1_GeoXs>^(02?2Td#wwl&y z{5qlE`tuD-l{ZLfY1a1W+s^Z@NNA4XNZa7Kql=0+n=jj0jig+Y@SE5)WsAqmp{;-H zKFz|T*%*Od$k88^pFG%%!GRVzG_SDhznw6i0PIXg_){_dWK>-R&Y6zM6sW&W!oT85 zKp1$dVA+R^)ROhHA8v|om6oHCiP~^YdlY zJ?7*1c#N)af6HDkHDO=!N~n>;;4>RV*7dkAcjMGG^L@1EE8Ax$Pu=aQj^5ulRFy?! zb*4=O<|zb7+19x~th;Tx2(xb>xPCy5Q}LEmh%@i`Z906Gd%c-@XzV7e)$gO{cdtZh zQHC5^A3!kg#=ksi^QQzi%bWEbu*RO0 zk{~_;cy}TsSDJdR7m*-<^gKqdio+9L-iSPfi|LoBZrAHylx1z7IXk9)rpvZ53igkV z{Xj1wBta8i&wszT%6?IV`CZ2Tbx-BIyvu)xvw7l5@}_zl5&F3PR>Vg$kPZW^#pKR=L9L_G%^PQwesifvyP;r|LT^U+_bgx)_&qak7+jwK=^$&Jd zzkTagXBxgW;zJg@D! z@X9+4_vi5CvJG?BCEdI|WP=^uj|4<@a=W;j+%Ds@$rg6YXwJ^$_Fxyu32{+EwoY=< zaL5Uh=Cdi(@c^SZxC5$_<)Go^3i7^y^@LY#IqC}bpDN#WKJ58X(j4fSw4iu#aZ@cNXKnhj;jIn^dv!&xp*z1?2R zzMJK+MRW!vk*CjcsLN#(o0t~ro-a685%PxFS#iu> zzbcdHTF!7L*$Steu)c^d_vPhg>BF?nML2|H3uJ+jo^>2B$?u0|DuycH+Q<;RST?7^ z(JHB^RN9xt-7mYJEXTdpSQ#dltXG|n%;1zM%N$UU9!0YuB}&PTvL5yXwveNY*A71q zmDL~R?N{^%Y)1)kWJ3DEumzf zxo57Lr$0KVx)j{WmI+Q9vmHB7OpoccRc3Hl`RQX z&H$9AH)@z6N_66{;Vn3#5c%CZJjaVN-2hukh0X^g<>)jU=yqeRY?2#7bug>B?~Y!J zy}C=iL`3M~McF`ws9|a2S*oMT_2OeASFIqap*^dU{4}ZEP5B$rN2t+|hew9>#mGj% z`NJ|t$u?qYLF)tAT3*b-93_T*b-Ln&c-Dw!$J1$*=6z-li9vmxZ^zAxzQ+az+*IEq zb4$}R#JA(=TtbC}c)C`$oIz;ueX?q;izAUlo*O~FkMl?;99Y-%$5K&;b=|sqwuGgBN#Azpq1h=x`vil}ve!65Ya1n| zq6g9ydk-@-lv}CW4mK;LVw++I{z>>ANj6*_&;3?rjJ*UA=;7uZPt zL!!L)c_Dwjte;Xt0D-_AjGIKM6rpD^JxWP z?RlC%6ARDitw1D{mLaNqb+l}ajS?SU<=!Vox{)m=73?Hx1Xdvf1fb-%9PPy@P>=#E z)v9)?Fs8#!al$#v`gax5Cb=s1=DC4KWJ2cpnMH{Ny4@Cv@CeFVG?ZXcMLf)_ql^{)l8X@| z=N4M^0Atfu)^a2BtOAe+VmX;#P{G7^S5;VS*b?5hvTG$(V1_;e=D!xRVmpHJ-Y}g= zFL`W=2+DI3c>=Xx;Ihst1yz3bavXd%W^}RCn`Wyz8Si8@Jy@<*W&dCIS3WhMS^cam z;YfO;^Q~Vk#f9pr2sxF^-4ClGSE?R)Zf?z(DK(VBwfN7aSWH(yWfFOiZ!6YK&)w#) z3YPR?L2a2JB2Cn~F(1Xj!0C9p4dy!Yh*|C!|L)#YOrne!W?BeQ=wQK^oGjA3$X)DM z0`Ah-3bph~op69~mS!LEmW8knCnIAD20=o05nN#dyqm)&s8cUlJgkZ}+O(B(JD+XO zXW`|w!Kmx>EG!RtM*jM`ZKGp#z<(Q6DII$pQXGiK9K!r+n~RSo7O|qD=rz)rq(_olT0gTZtf_MC`p+uQx(@+rZC=E)v%!4~Iy~I-m zkhT0Jh1Kj;SIw%dEyGz*kWn{PuI70v=`R%=9Xqa;#Ou`wXE*1v#*^(9vzVFtZ@NrH zntvxj)tHO~!=?9{nr#TXb(I_=>Y!#wv3294cgH)xhm{wlr+&neVsdLewi*u1P1HUr z2;5Aime4bBt)is(CRL}I4x%(|!hy^jLtb{Zp*HBiEyi-Oy|bNc zxB}QHeT)9Y%5eaJ3?yjFS1zn<#x z1i0C-;n8#5gVS`1t>jzIve6#kGMyA^PdWB@Bs(t07~rqEnE$Y5=d!!XX0`1Qg0)N*)bv4fT+1p(@G!&sJI>SVTN zk|8#SY-EOtT3fYVi9!%tD)x0oP}rL&HvCj}s>QuCYyS0Qgxl@O9X*8gb1{Q>r-mWt zqQH+~6AR4&02m)ay;QZZypKIQc)RV&#~o&z3F@ynbY^{<6>_2NudPxmQD84Fm>YU<+@Y>d6+z!PiMV?Vpa znJaoXQSTT$^47v)n9~Rx|`8K*^-z~HzDffi%!Pb_Uh}v*~_EopdPi*ME%mIdXOrK z!G%H#Yj|QwHepvxgXyvzA-DUa0FttLCCOB%^m)oGWj}<*2&s!tT2zM z)(=uo+<_ae~1(R53Fy zNUPoHNZRQ(YH0ceJ(*2kxo%NRH94X>E9hV zUN{$M`ly|cN>}@0QYutjbJp4kF2eBvjKE)k>L`*_o#;E7zFX=}YksC;g`6UFL-8OQ zB3%GggJ!G@C{=nTX1>8M8s`OWdgHy6zfEnK^=gY@Hlfa3xI0W{xS{x<6RMj->y=K) zGgVc~iM;v?vG-Y@JZw@lqUTgHLdCJ-+J5W&OHBOJKE1Xe7BlHiCk>ajE^qRJl8 zbU@0#RlGM9v)EdyR)WZ<1l+u>o$l$miwQ|SrlKzdnb4qDFF<0%w-T*@Ba%siKo&rD$Jbm@Olb588ut!Yu9H&%AKqCi(C`{jp%Eur`k4zi4I zd0+$TN`vKBoG7EgRlmcncz*vj%2NRG$Ie87Fzkwsej?AUS0W;lD2Zo)l!aHy6JVk{&*ucAT zF15aMN!Wi4GPb4EC5zbaVHHn@9~Bgy1Kc#KkayypNEfSm>Z@vfob%e!$-3LlBoye3 z)$8Ahr1+XNP~fI>QRccnr-TR(s!I{`h9R@UUm(8jLj1tQqL1QWt&Jid_fijPhTH=1 zYd3_bAr|U0ZTC6+E=v#sX=zmROUaRObvZTM)+6us#?I9e<#-yxn1@VbiDmK;CnzLE z7Er@S@hKRZ7~>WTb#hKcHpzFir*ta2p6yeR*jP66p`;>8x|IydqQDD;^1x(x=4+X`y0K%J>S3BP00Wc3G;zD_R6hH$81lZre7W^*- zL=h90KB#m6$k-Rd>Oe?oU(?Pvs;~})Gbpfs91xKMsu92eJo5i!E)6|P2I>H`$m|s{ ztRMLo#5LN5FDeQ(u}b%|o_xq+Wf#nvUnvUf(5OPy@uP~!aPu3I4@gpqT2dTx$EO<1 zg&sX25BFsp<%AMiILUqaYvSfkb)a0)T9i^$tE zG|ajXHAO?M^H4K<)a;(#q`V`41u!q+8S_OkcS)Axlv$o9^pDM5Ck`kZKR822kI-;% zJh}xhl2nnp)c#2t>ILD3n5Cx0)MCAF0G;>MePd#T$cmVY~4{T z&^kaJO&N;!Q*kvc#M~itnF6vGk91r>RrO){c=RxU z7JWY)!~=ctO`?R1$3keV&epbvFS5>~uqg?tPk*cQ2=2+_dAVHhq1Mq#z6gNCJ{GEc zX5udD_9mb)l7H{_izH$I4PpYHPhi%#59ZM=o6kciTww99D^CQD2~gDldYy;cj34^N z1y|9KLuB+{pk?o#UXgtaAtUe5#(B)~Y9?-ssi$X%6>>!aGWIEe>!IIl4JQU>)hDht z%_pQ5?J?OSAA@Q2DA|hI9d76mCU8=J@O1vL^8)Ij$Z-bHQyf%31^0rB{UpGODCcQ1 z<}qsv?cag!5sqW;>M5P6*EoJ}(lzz0>y`By6lfjMO)E1@lwRN}e&pS(v}|E6j7lt^ z?@|Fi=gB877@z_#1(?Ke%sl~$>Bkh+~hDYzXtmNdE7ul{|5T*QZQpoV7uar z!iBNTa14|N%uoSWG<<=F>KCHNxxFG!dX$dhr#`#IH3?Ll*q>acDu+tlEPH4)6Pt*B zKvq*+p4wL2AJ4!+Xw%O*&xO|?R9a&CIRlfN`|f+N^E~XyhZs;R?$S7Vo{6mEHuh1F zjuB62y{Kvmx?cF=m)X-z4z8My8fIZ;0r=|OS8aNIv`fQ$KDv*ConUP}o1o5XWV=n{ zlY88fmAfyGcFE3vC`+**3h+QxgCfOOmOr>VSN*vLp;lk?-;9Y_e>qy*+{kBQi}Eo% zPFF7#3u1|eEk+~;Ujs1xRGCQCwj<{BUI$}m#@Doyy$0&*lFy&)@L9QvQ0;gve2-9So%l7&rW9z**glMM;024b5VCHE!-!RMq6;mPCYmSB2 zQ_$J1C|xq<1!cCEk1;ps8>Zu!l!1>lWJ35Bc1*b1Hjk;M&Vnhx#h$Kt7UtH!clrGf zW(24{05eU+JSAgpa|GiovC^N$sdr%nv;JlI3y%2D45_R{gg&V7)%-j#(C|_^&ErYNg!u7mQXfWN zGUi1GAoD5E?Bhh&m$7X)2fgsQzwc(~PkVVNG2ZI89?ZA1nD+uKg8S(u2a~iD=%R_J z@vcW?3<0+?E?nv5*V?3PVK#u?w|s2p$;oBld&ehCkvn>xJRp1T)vhy`brEjWiWwJR zXJt@5%pT3xnh$pQm9@!EgFmJI>khF~TW-ZNr$4I9W$E}$J=MiNr((1`aI%qem&ZkT z^>mazZr|ypjl%D^zwDv;4fcI44r)vGZSv)a~Nfmvr3zWVK@j zGgANRKhm&r?!-sJcY`~hl%^nu1)}+lv)uZ^Yq|ZNj}-%e1rEBN{&JRz6yt6IHgu)V zP-wEr1Z*o@T2#{N{1w>Htf-LLTX%Fnhzs;a=-M8iFwI?bF41tSv>$6_nZ&&+@z{C6 z<-Fd3CBOfMD)zs3uiSO!A7t)p-DB?^4-}=!ymZW?_Dbj<=qX)!TD$ksiF0N*b{L=Qw{D)tS4Ih<;!!{tBZyY|pvh8U;y#2B%`jDaj_1qrh z#X~<&zHDCjov$(R%%j<(K3b{_NIZD`@Fl;amNzfs8u!Pine;zT7L* zzI-_j3(%#5V8Wwir`pFjyKwI>-j_dC*fw&0F~QEzLDCI!;(}SY?YQ}JkLRa5vXSA1 z<&l*;*7Vw5<-EJ{$=xF4e0%wx)vMv-@~qo94_&HySl#g~Do|dveCyln@%QbtH)P;e zxbusnYT=uKuq%w2w0t@Gp#CxWVxW8ZQaDjR>tZsV?N~0hnPkK-9wfjn`2~B7m`X_> zHLkDvS0S!#pQGk}UtWSI>Eza{`o6L*>F@O>-%MYP3qBWeM)YoRB;G5Zo@;mF7so{r zfs+uQP{pl8_xWqG@e4jJ(vOY60+Q+Dwg-|xx*OB=#1G%>vIq*8B^~ocC%o(=n8h|Z z38pysFfvz;-t=@o_r3P`b=l=|0dJt$Bk@4^HK~J2Qn|$2+RfvRYm>PeY+uu7-xNb9 z3GaK_S@tj`@@p5allP$v_{G?14V}_KBtBEp~vM`E3ln9O*lZKkI@%owmdRU=6+QF&Ksv2WD@x*s`IUVFTbkZHfTJYpGE z`DUbXdUX={S^r&#!l5Te$5-lZ&=dpYds}P7;L6{sm2@PJ;0-kkld;`!<sv%8})`1eV#L0B&FngEm?V(=?mXE`KG&4LD?Ap2@# zu;h>opAOq@In1Fk2jI#LHsU7%F$ZcvMoqWVt~n1h9U&%T+Y2)(F(jT;Pm>8xb=C^Q#NS?#SJmafshzb%u2mhx^iopmh zL&8fqZ!U1$$YsMBvhK(=e z_}@n}S)su-GQ-)hHgy-b2o>#;C;Z2j5KgmH|5x?b5S@>7uSwm1LAB}*jef&Z=sPjY zOHvgFC<{@!-$sn2wfioqU8jjD3ytwHoFU2ULiTBHpv>kd%+#Hc9{^nU`-+!!9(`H{ z0AeQ|wZe5x?>{`=I##2MIqoBkD1EIkV%9%37TH%^d7-Dnq}Mz{-npHY!Uxc7URc0a z%d|@CHy0py2kb4Ie2;I{vZvZ%RTs-JXSBmY2l-iQ02z5Cy*j5!f9$)JuJ>eS%n?oK zNB8!sg3h`&Z(7rc9YGptAI`?MWNZuX#b;Mmvm|btS8a2fMtP98c$mKIVAGy!gwx%i zqpuKDUAzbKh$LBh@a3|B@sH_-*qNT^BjQ#D%O3IDA9^ns!wkO zSn%1MCL+-Y&DoVmPm_C=4SVw!kMwIMU{4u2>~!6@WnP+kubKk`OWNd)Y}(4)7tP<+ zor|r7LCu68T%BcRz_&QYU1e{3>0E&rxmFZ_cv7y4oJ-U7s;akY2IIhn8LE5PSO>%~ zdR362lx%~{<&PS_;ezeaLA)w5bX)Y)VRTXYpl@Gw>>)!@ZM~)==G@6JykXYv(V4!L z1NKSp_!&A6xiBg(6=Tawm3dq~w0vzy608y=E4|n!;&BE^qxlE*fB|d<*A^yft?v)6 z1s-u9lsu8hKN({jq|4NOS!uPRe{yNO++NXO3qVj=Y7rT(X)P3x^9wqdOc4P2R*ZM*_)8OX~wwC zrs@vjKRtvXV_XcuxXIDDnt+?2#q@@ImnFx{vS{AMxTb%7Z^z*v$6jwjFVT2{MVqZ= z(TIfMNhpTC`O|;LwjM?g# ziL&s|9m&J2pk9XeW_8d+SbGU4xiMHH9``i)!eYtm{gSFg|{C)V}4r9L0 zRv%8#z7HoKexCh2+q60HZ}?9X^Le@VaJlU8^YGy^qqn21qltC6S=Q7$Tir3iDC=0> z{9e{HF}wVEVs^8mca~Mw!C*C&RS(k`P2n-Dpm2sGF~&QH5fsiMIK~hhX|uDNy}kdC zHVqFivsg_uT3K>3D>?ZeURHQGgFx{1_D&`cf{4U_00{&_I1WcdBGu4nV`Jlg%#+b* zf|?o;fj}dX#z-Uq4o8Lu(Y%TOXE-suOmqxVLmShQSwY_acoKU%hP{bFNCf&HXBOih z2UbjYvLk`0hQ=Y_NP@8=8mVTiMkr&I^)~f(RCmx~XvyKpF+nlj|2*rTc%UaH99-@Wez@2N7qy**m=a z&m2u1y{s};cnnbu*O5&7XAT-KA2V$u zS2&>$SvDt!UA!J#T;J)-ViUN;QTV#h*!~tpJM3|Mbo&}DlPPCT6IJW4uy;h8##_(# zRoJoQG%HBu3VF37Ow>S%q+@$%aiw1m#&=tpQJ_x9PvRcc<$H1GOs3;_SZt^m&cBKz z$y)<0##juU^7^kMv*3Q<@}rMN5@RB_TtDUffwyYg-Il5!vzAomVfLF6#gC*A=}b%x z+26HKfdCQD(P}`nmgsIgFY;<;0tOwxs)91c>TL_TrFP8$rkPsF-xPJbVm1x@-(_Y> zF7%i1*e$skuZ^U8Xm~Vr$DAE|WOJy}Tk>^#Gc#cEk@=197bZC2hcO0nJ-Ykr9oetW zGJ1`I*7AN5y26X_G>GJpnR}W659q?K2S_obkSEc>En(eSM7f$(9IE*vk|=0uW}ENK zd@t&0&l4{y=IWD*PD2s`3JSzrwZ3wBxq9leh^N)u6+F%~>9gp>b>u0pkX{>c3HlgWWM}?Itk~9Ybsfy>={5%zHwWw?5vKlRo8Y_vC7`%&BWdGY zcmrxaxFACuC>{ff@&^0W#p5MIINuh++v{C9`aq++#R&R#&7hbNK-EWofLpabdN}ok zOw4$_u5av={ugK6F}*h5_}2knd=pkOF3TBg-h6UP_v6qZkDtykeEr##KVqymSNXqg zJDcpx=>lz#A#PIc!BK;32STJ|si2xGMnqg+ayEqD%|F>c-8scI_0)2XeINt7kWheh zL(M}@X;Y55A>Uk$Vx5liLPPU{vf;xBH!~pgw0jEV)oG%rT2WrSjSw*aZ__<>-1I!n z^$aG$p$Q>khkG|Hp|9apsXO8|7-HjecE8Ls^L#GkvH@a1F{Sm}$n9n^{G#G2E5Nzp z!RxbW!oB*L&ibRNF-wt8^v~7DI9a`7NZwWlhSfQWTB%>IxwY+^&~)qjvpXL~!x*?x zdeDcaZ#KGb2=KklJ37mQHwBu%jYZDeq(!jUc6jT<#pyRb4R~~LW=Z?%aoPCx+4SQX zEnRN7eqP0s&NQx5_ff}hiFWNi`tK$E_OXC_Z|%Q*xcAo1B4mge-DFXfr}SE{&_DEN zhXkb!mL~o&wfw+302#vVwJYIpiuPKF(O5GoUNT1b5)+6fi^Q7klO)y{;X?w7eGcJok}N@58&2xS%WN*^+L) zi(YIJ@4|PirlTT0h%NO1?{ojnl-((|6w;&=GA;xMHDGVcg&80|buy6DYjD!7I*$kM9Hf3W1|=_k zIeFp2H#*2@P3nrepK;{dwxvOQsJ%w|FM6eYr4a0@(|>7_WT^*ONSc^kY4({bFMLAp(Z#xgP5U<3rscnwM8Iympi&p73+q-#z)d zuWq0AMmfA#MtGAItBPd#2XNW!k|n<<9u^zwXK`uJ0TyT_b6kdl9yCJkywh76q`jQ~ zx)J9>r=9NNNR3MiH|&Cd%?QK^Aom6_5tXS}Ux}L*Wri)xd@^*n;O6XBGU%<^EAq4{ zZrc4l`uW@pmGixEzcw^zQA3i@=lM76B8TVH$jk^xD?{aW#XPYiu%bn7tPPs+Wn{BZ zOh@dFP}>vP)TdDcgqW%5L`+C?sZ+ps%2 z`r0ctT|7IZ9;VU9K=N1O)^48X(kQkpB@Fb??m9UkyI+W%c_D?La&l=o?`$*(lg|Ft zD7BW=XZMm^7OAO7e1^|)D6v|sIlS_eue{aoZ~UF37j`ezaK>$cnk*dvR2Cr%*wxW4gE^W$tkASd!Nd1|N z7KYZTmO3u4DLuh9F7uOLN%@ zN9(m34<`!fuDw$G5ZoHJ0DLaildr#5Tho@46ZO0rrAZEX&DX35o_)zK zvmQ|%8l&-ukKC}OaaYsNR~??-^p!~(iW4)jA= zb`|4*@}f!5*b_|+J{#@E-wUGiFO;gFK0T;^e@Q{9Je5?`bRnwFDr9uz@e>qrU4odK1>(0d+%R|Hb;0g&@Xr6|~~7 zXX^$pU2Tx;8M4)F9T@$TV&`7lUk~IrGVqSNu_!S1;2tx~SMWLK!K{0Je0^%3Ffk6d z`g)O~B!I(mj>YZ~wPg3RNQ$fEV9g^L#L;U$^-cuqcD?z_{GWAX@oe#TpUW&bM;D4e*_r=@W zXWl;1+08Ym{5l^IdH2gI-(rW2h+6dWIW_qw_av=9x&19g>pK^2oBsV!ddIQ;Bt&I* zdr59&;hW-p-WrGOY#!Z13oBg$y4Y7GwchgM;KOfR4hzx8Ei>8m8DfvLLj)|`GXH$t z;rf;L?2TT(^AXX@|K(W$UOaeA%BbjyiYhd!6(#ioWVz!?jlB(0S^^L zLUOh4zYrR3N4W-^3yIVIt*;p9e$A15?YC-rQoLV6u^*xQjHMe_&J(}P;Yi-^V&4KK z?3n&;D52^=dGUTwX~2qlC<}%=Ck}$d#Ch3zWm)r)-`1B~kR%(>dNKl&Yfr zV>m52K{RN}IKt9eiA;idY7_A`A7?zS>PHpb_s;@mf0q^cnplOD~bpD2)nm+4B#x)z(&1y6akOI01Re-Z$N z;w{#{=;E+t1Bn9My8uCyoiGacaZ+HrT%D~H(mX9UJ?FEMmKvjYRwUlcC(#$2>S7cn zq;uE;4j)$h%RVn#A@ZT3FtWHPfm`8+VNsmtWvAThKP5;PB*h3ou|2rBO>Dw0fo@4) z(nd`F5EGb1TDec+FB*tv1&BP(_dHD@NEZdPzm1Zy^%~O66K@fo{t_k=m8sEXp0uKR zb~5nFplXt}pmZw6LJ_FD%Wu-n_X=OB|A3Fn1<=}EnN5?q&Z)Rx4*fm}MMQFma!_I@ zoX8iqTxG9*Vc>_AveP2q7e#W_qS+oraX(l2d0pLFX>M-}12j<=nP0OPHiSJvBA9l6 z(w>Ml2!h|&@n z;5i>S3Hdsmpjjd0(9dpvaa_#GR{;wvcp_1#6} zD_oh!wYePprm_Ne%Az}pOV~fCt(&j?JU_>~l5_4x(^vDww*Xx*@Qe$Hslw&T(LNCg zLau;cCV?zgz;bM$)TE$)r{GSrp#HluGk2el0o6nY#9~p1ZK|8(y71y?L5RAGUxKjM zH^{mga<1ZP2;E(-Pejv=%L{1b0u(mK>1aN0fk>`xTSaD~R^H&qFNV`xmS_ z24sxf%zqhB5vA;p(OR#+`f%W07)&(&rB-x-Rb0IGXAJa@k#W@MwM1xLlDE~%gKK|g zuOHR3mOfTX{%(vRurJ^wz?~xSZEceK!*iD6ZbTc@Wo192r^rc^XKQZJdzFHpxIi79 z*#3r}E0CX)5X;4DirbVWUFrFl_MFIM{jE$7yy^zFu?y2Ud$?=&3g75?qw?wsG>i>P z0>CVHxy%qyBDNEDECKD(sle_`$ACgUfHl}ayOpMuQs9|1OYlAvWLUMuQ5xSs@xTI2&Q-qJ4FqBzt(rc% zx(?sI0Zu}JjhSL*94;agWUMgaGYPUnaix`6+a0=eYN5DP@u2x_@P8{IZ`3)GSi>S2 z&F7JvAQ27st}9pni|~ea*%t`RVbIj6s`G(02#T-><=#f!z4z%xG8H-a>2tbe&IF+c ze5SX5&o(;&>%OJe9;ns<>6i953*U#-0-uVT`802=D;|bOcm|sut+-l{mZ+6QhKAs> zTs0*rLhn3mgYp_`Rg%JkrGD;mX}{$M8Fr?D$3KX@yUA^ngHHmCEHPktZjkfrr(;tUckkY9&HJ;tLg;N&$s8tkPrc2Vy6? zqeq*07i)XRuBA8@{qht|mAW3&d4{d4twb>ym#Mc^IAXGvpmZ8bF3^NWOMDD=DeSDt zXi@fyMjl@>bnhuqiBXB_Z>SBB^1T4{Ys?EU8;)<6N)43eS~0JwhW@;8xOJieX5$H4irQxS`ud1XK;EVxjnt1Wia z&PHIGGdeuU{~F8xViLh#;ym0pcpPn6+-PZ#OKNb!{Mf9q6ij4%r$n(!M z*unY@+@R2nqdczACPkG}bQn_kqEdTG>gQySAEG_3>XlZa9S!b z73rP@7GlvnCFlP%_SwP_^JDg6i!dhvM*)7vWq$GF_?BW9n({p~g-9|kRwt7QL z9)_O1ibZ@`#!q1ps>q_ll0;$Z*6C;)Kc$u5RRQQkTd4ah&4Zrn0N7mH`+yX?D_7c= zsJ$%#P(gqo&cBi)1*m_&nv7bz)(j)c{kU*5U?|*Yd0bwQKTs?tbzf1(hC3! z@`rtN10!8JKejLU*{;`UazsV>4_ijtodtFP{7WQDM+?KK0eOP{)8?5S$to4yfUA1W zO9+auQSVZykjSUbdq>OTca0Qv2MhPQFVElXkE>ftQomist9UhRQ&;nHwur=My3_X1 z8Png+q(>&k(b#M|rIbBIlT~)&)bV+5&+rDEm_gVZnOl#;CqQ>4Q4fw>XNw{_@)qAp z-9<}>ru4RWcxxRxZVMs69q0Lp51}T9(0fNXlK)WnxNFV_0 z1DJ~9e2K?5!ES&;?f^9=1vRjook&Yb(uw!Y^1Q&s*PM07;{x-yEN4>PRxI4+B=2gH zkrwzG@YkCP2g2BL)1R3rAtd>baLzy`{ng;5q_lnl|NODsnXk&VF~ygDo*zid6pe>U zz_Uazc0ZuiMFs*Nex1hd+KQhA;v^p5#8{h3f>js=WP$F)m9cWyB?#AFE)Vv(l21}M zjtsX6h0h-Ay;5aYxeO6uL*5?4q_lo%{tNX*d>|v>m$4rl@CO5bL5{Z}ml3dQ{xCKC zTOSTM?=S*(nf<|3?ya#7~sFv34z_C;2Hh(r891BKdU)9 z;7Jg|m17;y5;(+1g?jz_4FzQhifhu~@27&E*q|ipjmkk#Cp%S{n|k#^LykzC+5qk6 zT1bwBcBKCVLrtV+{D$t^g!vMYiQ{Fuk7?yErZ*%^V$y`Q9Mjc^IARqkSK;i2dtpF> ze^a1MrdabS4*jdqY^F%Fe;I?nUfe1Bx-6H#&YqIvbp?x*9r|>UqaW%@3*eJ9R~BLb z4+RG_cC`d*=GYm8{PulKD&HFCuEtO8)SI<^`HONN5(mCj>?*TnTvVe!*|xdTpJsY!IUeUqSuwv z6&kiG9#mjP@8)Ty+-b@#-EC06(^Z#QT^ySkRC_BWlejBBMH;bd~~B(xcG_(aOC zQSB{L4ImUOgipwSJAEvj`c`#)jr8`u=_f$2Af}2fV5|so{VIq_n5%%Q)#O*)KDdQ? ze&cX%6qSh{(S2_IV}uNqia+?E{rJBh&sIDEV7^J|__K52Y>bo>hN95yyLBv0Ju@&} zPT==9%A;FzTTMA87Xn|`(G{lEE6tj?RYap&N0+73qqpme7z*3N(s48QG4eMk+m4^B zK)7m!>%quI)&rt&qspYhGsUc?p6SZRT|3dwu=ByX&3ytVfmw3m;cYl0*{u8tmHmu> zle#@v#Wd}^D`Ra(4K)-y#|3Pf09G%t1I^J-yUxm4Le5v6uYJR$GLK?=4;ASro{T8u zIJxt$XXCr(6nNLSn%`c>Gw5KGBVnXKUemB$PC6R9`?ZHJg}DazyQHN(_iL;2p2gYs z&*HrHf5&uk9xN~PEx=Ft*P-F=ba+-4=TECP`qmt<>iSZ2MW#vv*0-T5Z9ivF_!5t! z%G~>o(Hu&ycZR^y<%1{zVZ)nhw(_~9ifWV_4gHnqhEm5>mHTT?M-{SDj5N3F?fyB7 zdFC4TCwVDGa_-RjZ*Kj{VtU21*KW64a{W8M)ELBn+Y!3;hway{V`TMFPycujKQFhD zf`N0gw_*aAZVgx?k^qD9S9PFo89;$cT?4hBCd-T>1Nh?S{2SKshc}Jp@H`4@ApWjh z$b$ej9Iys8-RZloIu>RoIcL{4y_y|5moB3fd`j?h{+%G;o|#7I5?)-%I1R6)t(K4I zdbH7$=~)FmMR}Gs`;t~*ZNsCrmwRe!_o3vU;4=q~u8bYL$O_jbyEE`x&S&;bt5@K5 z{iieRShd)KP%aIPJ;yJMnSyNx2OjrUBHEm2gPq&Zwpbxr?GTC|S2e;2E+S7c8C)4v z=R=Mp^WEHv-6)fJPO8tthGca2Nlx6UrJFt_g;OEiz08k)2yI_z>6EDRDg^E;6 zHv}jkt|14I>PBgJ0H}maw*t2Ts3+aiOXhMxd|fUL4Tm&;_z9yvzQPVcsX%}Al`)Rx zry4%L9j2_=L4fINNiBsid-!ZLv(poho4J&Ktc2HNlOy_oc_BE{y&+$sA76m&qGdbx z`DO&?DZGi;F2^M0)}C2U)qP}bYkxiic|uf?`Lre8DuZVL*=ffror#@_$rCdZ6~CTf zqjk=BeYh_21^Ea2Sdyy<0ufZa>ox6kemeM>_qXCWb9U_YA5;l}jS`FT=X@U60ma>- zqkn{)L#f08vF1sVl~IIH76yezj^OCA*AO0Th2m$5 zCsxu4Ok}zC#!0y8u1r@>^Foe4ce1+^wXUZ1ga_R+w0Rr;;=)-MYsGAd<`ph`Mu!lOg$9^A;FQtGs(=$x zAbRcB4Z}G!HyN=%Yuv=ZLWv@M~!6;txG z+6PY>NXC57Tu?xE=cpe1x_N!BF0ab%pbPaJc!}SVH1b;~cU^eqm<#`la&0{}_wiI}h|_$@?{C-79W|x>r3{x?ayQ(G z!a|h9FW?=&))>;5R$%f;Sm#+Z?`3AB&RbHa=A1hp7C{wK#{}Xg0Xz|RfP$e+klGK@ zkcbgI^E;6$iRy$K9EatsitztI9*bPZoDeM9m{*J`OoJ|vy~9wDR6RIBC^K*~e&yt@ z`rLl*d+)0_EB8%n09w@a{|m7tPD zcj8;!O!4j!i^pG$nS3)^{y5*8!3w)~?0HTg_%jjb*Bt;5SE@eddh{}LxkR(^qBfW6yZ7}he9zG8GM}nXqJ@R+y44<|Ti zTDFHp@Cs#7JejHkN}0Rjj{rpyzstx9N?B?*r*S-Y5W;I}$h176H|lLgObOA^4DGBIPVZz-1qfYytI(6x!7mii@PRaJj}Y zEr^@Inc19oLZO8l{(X_#U$QllH_SJ zZzv9|29Mr)_`@FN*Ja~FyT0G7`Frwuzp0_`YGbrU?KNRA)*q-6uESk_A9IIymT>R6 zYu3C}M%;VdVtmGOR?eL{i3&h{CeM*fN1>PhndN>kzlGsZj-?vzf>l|VTV3YNe(;iz z5RN08n=G-tri=A#NAJQ_bLC3B}f8z8q+$eCI=i8Z4G^T zwB3OcP5~m3(%eY}LOf(uIM6eZ!s`O$UP-@-Wma3m#Uk;^bdp>#`QnF%hjXdE^t93b zq0?iy5JcZ^Je(GZ2;sJ!6b7l=^Cl6RMxWJUvf#*_EZlFpWYzF=JxHG1w#qG3W1oqV z(Pew)rfH0!XL^?wxR*+L4I{z-Ae#s47LlIFM)7Kj064!1ub<20{^0+>F}_@?Q!0$HMr+b}Zy2m5Cth!{@srRSz5V zcc~zMlNlqL%@){0n#S_MLc*HyfQQA6;FT4sFZf}=e)SuBiU1F|g+36&dD}6 z>&hZxm=9!=XB2YYf|8e}?yPjNklN~7Pd+u=YGA6hH&^ahG9iiM{r)4#nKJY$rQF2) zjN+=-g99*jzV^z10aCe+qHgzNggGX!WAj)a3(-oLuth=+4V3TL$k6b0V4p09rd;fO z9*6~kW~-<2b}Pqo71WUdMj}BRim_)sS!@ON%`$Z|U;wJCxjB8`ruaIWop~U11o3(#9VL27;gqEG4$*A%;!XTFF7dL0?!rRvi@8X4vRzI^3T; zy#V8(!MI83aF?gt{^{S4w(+~qzt7EF`tbDH?$av>dIwTO^9S8J3xtcLBobR9x@$+1 zL4){vv!%6QHY%$o~PgI zybh~|j{kWoiRI1d?onxFJ}fSy*FBsmt-A75=Ezk21Gc-juX9J2LLMEYoppLSFLU`J zPbF$fSEKiQ+z}2$tx;?d`=g^RZYO{4ZxBSVW#4;;M-4dk{5Cwb4+A?K;)e9%AR@`A4IMw*i%z3eFJ|lA1equtesCXYh8Bu6P3F@tRi?mZjFx z;GwXBxMj($G@ttNt==<-A9~NoRBB$rfZCcVc|UlAS!LR*w?r8(+AY&H*%c2?zL7Q3 z>jH2WRUl3CGLvF6%kk?=KNVJ_oQnPhK-%5T2=n9v(X&JR9T9dC-I(m?j9Uqn#&?{O z$2@mD4S0sZZjbz4S7xfzs})%hH3OVKmQys^y0^X*>H$R@9kq8v7z1p$T6TWip7XO6 zD+{25i|*qu&lozK0NFDTYpli=ZNed{`PYrXdR*YWfIG)?QST7D=Nk5RaX(UN?N-5zP}sAs-7oJJi15}J*w0xP2^JdX zPE|d0$q%^O?tf}^2=z|$W8LvD#4-1?Qnyy6Ee2&(AX`c_{kW5`lfD+Ao&nqZ7axIr z!ESf&oIg9Q-Jw9|9>H;hdNtdE{ zk!!ptvn`=U*D*-h-V0`F$7KfR(=Qy;bo8Z1yvS0dSE!N@y>)P{i}&%%_wUysr6EQ^ zG=avO)WiJDN+hnWz+!4u?v{X7=A-t7viLE>;$FL5(2ZNY`lfdo6_|uFr!1=+V|)k( zvyH0*o7IitI8^SMJEc7;VcD6V_K)xlBR>kkzm4ZH_X>?tlpb-yzRZUVSHB8;MA>{d z9sDl;?UKh7rb8bCJ_^5MW8Z9xf>_sy7Rub2F=v-G>U)P77svRokjN%5Mka-|O6ZyE+pv*0N6a4t|F!>J zva0KhZ6*5R>&~_jv0IIzK95D;zza%db{{L8HnOK2rGw>288R+l?cMaBzbHJ-Ag*qJ z*olu+gqL{ag@L4<5nEWSXZrpM^zT-ubgNg?tDT7)aco__I*0PS6gYgfC2b4Hmq2;2 zS|efv6aWbJPSzjzD)dZV#&x?eTHL40NrlK;+HFmD;Kj&pi8;ysn{>j1p@l>Gmr3iZ z8BT@gOJ}L(2~Hvrxi|0jmYovoP@!34e%?1Ya6u;)oPb!}qlTQ^*u8pS_qkU=d0bIz zgpbTS%gVAVwWkL!>31tl)DvAUl`LPN1iiD`J9c)wHvqpka_aQ1r`-oG-MJ$x{Pm}4 zM~v>wXZx-vbO_!3v zyeB%f!4F>eYJv^yxXXg&pWH3{SzPo}6L2Z_tnhFpkHE!g9_M?;zYhjEGP|`(>2$`o zR(sXSk(1ZCpJ5*~TTHlqv47`=B}crl^n}#smg4OxhFhR|FdXj-f8DJ+e7w*os+FEA z3}T3CU{|(CUsBUDwA~$9^gWJsJ`X{`2QYB`b|zeRWj+Ykcgy_Zx2h(QR{}RXv7mO3{%e<;Ix-fQKFPd))Vv-hcScD~k*087mi2;k#)ZwQ@LC@@0ru<}vdv{^F8R zPN3-->^jwUVb823u*hV)1A7*O1#h07O6aOJfZrk5*M`mU%p zP-_L`&7Ky#!cFw#+{6-V>{y^-Zr>f(En)^Cl?Tz~N{UT?2+m5-B+&eg1%u7S#WkDF z`h+bq^Lu_iO2L7Do{+v)w+bV3nXIKN<}{Mo^5HTHBML%L*a(Vb-DNL9>OsRq90qeC zGSNNdtJ0SsI>VN>b3*B|KK8CuAN|SZ5`ic;vMW+FVQLWUk)Q-TN^t2Datd=fA`X*bJg0t{CLU>rIk8BAbLc%@-+Ms74C6bk-j@CBR`~) z4wIj-j4F$c(F?P&j&}(6@IBG@(l>F#25l{B+IXLuxO4NqmiS)Fxi<;;_54@h>o;d@ zrNP2=s9vag7xWPYzOR86jTZ`#@MU41$ayKP2B4BJ{1}#xmtm#$nN1=nVpcwQ8xiG% zT&mO=H%m)y=Rpoh%ROx#7AadcMkBM6^#3imWpRmHDM&t$AW*)l@x0e9f%|PmH+_#QU$*zB-d^t|IB5 zHZ>(7Tlt7zG9a_hQZg*}yrWl8KqPut{1(|nJuqetm@b{fN?T~C&8|VLGi&2-L_9nt zr-{l|%1eyw;CXUdApawl<^)6z}>?<`eEpqx|C8)JUZQWFj+^b%5#VUf8{KnL9Z^Ey-0B%#FKMf&L0IiU2n-_Jy{@HwF32O6A|#YS2c~x)(oqE z#`X_RC3vAD^1NmwEIK*|XqLE^)|uB^;@x)oH78?72mvM`B}2ah1e1}@VQ!U7_ugT5 zFHr#{@u_>>z*>X$?XpdZn5K1eE@FtscPl5(1QWS>iHHEVH|jRE`aUzA@AvKcWqo%! zD%||bdtefYl=^wSn%kpzpn8o<`yCpd^u?R{=wL&`nvaq%6bP0E8E`4|1PD4Xf!`@4 zgaYZgmF-Bscqa-fHN!cSKkhG&DBHzlmy|313IcG+aY#vnDEakVJVb$gom)vwMKkIw zKzT9;!md2`p&6#v)t6K3Ga2fy?hSpBOAfa6=MqBY&)A|Uh$;ZYCqNbMS==E$$h?JX z+%(_N6PMs4UuaeoJ=4%Ep+UFQNjb(>g)o7+TnWgyVaXrt(@`Qe-zSh=Ul&qUjC`oZ zm*v&7cz*xe>Ai_hj0JWL-n}$biB(F&P41g&$x5AziZzRoMXwSi(W- zRDT+(arg=U9c zCLX*{&VRuuQWnPIHcUG!%73vr)Cm}nm)G8!a*#PL($IUFMlnfB}=YvSGB7+B7T7&sPN^E-%lAGiyt2LK^(C(r@d^Os1nuUX;!vcJj8}{>zWQe=^JU*-Nk(E8M~@Lr}phk_Iph z@QwY_|1U}Y67rwr8Mw}%C|?WxxiTo0_QON5c@w6B=xf}U#$`CO5ppT3DSDw45!#`e z4$7Y7^cOJ?n!y9Fi+%x;uaFS&-|%V!RGDd}6G>+xm)*{`HLgHCid*(#__dgns% zSyZ-Uq!r0LA7E1E59FIc-AZ%>@^i|fkh_2}t@b|tz~tw-`6-?83j$^QTo*N#N+Pa% z=U(_l?D80W`kWbbas8C&(6hR`Zl^9dhn;#+I(p%(`z829tFa;4r~Lc$L#dlJ#^dze zPQ96O71{bdRNBcH^Z4n8XNX5J4;MQ&>*z}Ar!!q>KYnoPA~yB?;0!4+@9BnNTNgP< z?vCw`FvO*u@prZdX=-c|{36p*Ab}~Q%{1cjgHvuLMk-1f0p*WlVb5qN;30R<^W4t~ zG&|wuAdUqUnI#nL8YBb@xtTYQeq_Fz0cI-o$zuCf zocn~G`lLv6UJiWs^=ZQiWNtSycOx9@BC0_CZbEK~sHb+;v&}&0MjpOLM*%cU}>XE1S%7<%yaQ$kbv&Dvk^jy!$OoaNo zih1Qqyv~+G_CMNsCLKINeL0LOdqvHjkluhwR|_G<{A-$WTUUUh%>pSOMNgOyT|QX5 zTqWhhS@7<%nOpZrY2@(ulLZq{;&9|^GlE;+GbOaA@>nuum_BNEV)Sdp((Uk zzv6-M?St%+gKn3RA?Cp!G^(&{whC{p2i*ATB9;KWW(4&IKyQ8ZY8-^tcseR3k=ZuK z%WYhjkP{6)LT|e))o@U;zCN@lrFD;I6VU%I(qn7ax2At-uUx3E@+tKj7y7Qfo@2td|4e z87q*Jh`|cgK#v3DLX3~`jf+ki7s!bfE=p~mkrd}QHUo1x4Ctm*>CwRkGgih+Rt`@C ze)r(Hdq~`|n`h&FucJ1U?mbZ8!ad&Z|nJz}q&*qsVV; ze$I!xWQw5EWS1;eJD)Z*r%BuANc<)%8~~Nz{Z01Xf1@^NdeUeJp_L@H)y&>X@ZR_> zpD4*r)PEA)UerDkqW#NNeq7*_f1l89#%VL4YXo~?uSoEK?x2o3$D_$27EHE4RIadIG@s| zfw|m#;@<%(ACW4PY8@%6@(Tco86}C4;A6Kozs@@(d-wVBK?8m>f9A?t&!4L=Y=|C8 zW2e->(MlL7Ty`vp( z0?1uL5H@z6CW_g$2KUwR13Tkyf@ec6v(p=Y7G3>H60Gxu6&@36mxV{mzeOU+kkc)$ z1uY*fWoe$mBZqxWD7B7MMIKh4=*R&7a36gfC$>mm> zFN7mrS9d*KX51!-+6Ez@5|hBUp04)pLgF@V7=pbVgn&YTWDtam^87`BZa~E|?c8MIl6gU@hryC(vMQG9`8c*|8ErQyC zhwbHvo&b?0s#Ig2q7NC!cyEjZm@ld5G+F5cTY)YN7${jemr+gFRKOGs_@^en9Xu!` zlAQ>dzJMrq9Ki8`znau)m{AR6w)L05aHk#6ItMhuiN9D|sq&Fmi7eDU`;+8zbLph> zgiCOq%BrKHb0 z;VqItageYkSzeQq?a(N-1qdy*e5{WLjUe~s@IWJy1d?O!(y=5}hv?nRn#9(Osa?Hb7($_-KT5eTh0+M+ViArF<+cTwa)? zS_N2rraLV_Bu7!H!x*9Tln5S=v@-Rl8rf5Wr>xEOtPGmZ@2bs%oh4cL4EtMDVFbS( zpB0wgaI5;l&f63_#~>9KLyX*JQ+SOqVrz> zpKn8wK%eZ_Dm~MMImZfDZ^vtA+s5Ot_5I{K3x}4dX4~aRS4u^i0vjmVXer&*=e|Kk zBMD~Dfm(?weZqaBPL>jILR!kJ7GY2{fDny>MRTU2AOu;@&{oa69XdxO7^QJ|oEWyn z+w&q9RI%}=M|bHX{N#hxPF4Dm|4r9_R)C#jN1j-fwz+@-{P<&2JftD9m; z@Jp($9v+aWG=5rv{UrD`qi8Jwavf=!TmbL1OJ{RBPAnq8Nivh ztzZ-h+@)B#u*$oO=Sd-jOU5UjJ#;Rs@`_N4=W~WZPDBPDgT_Q@MSDS&&KlhABil&k z$i@b~Dr`Id1E`4VLvN9dQC~`!IganYC%QYN~0UY2VbePy0+e zB~y}wObaE&NKy&2R5PVzvLs2S1tBC!63?_~Axwl2rbR-S65<;@{c`?*^SaNuulxF3 z*ZUp|Fuchk25uh!G`_J-P6DI6wGV?uHT5>p|_hEF9KUz8`Rcb z$&^Mb669alj%N~D&K~`2m?t?KqS;aO%b?z-qiWx^XPM~!jVo=?Y;b|>ZpWk=Ln-3Xh(n)~lF#%XK=}a%!qfK;bggG0-JjB+I zT73JW+h7}+}3fTM;*!=jCy(dH3^L20O z2QCc#MVY?k`w*b~QO&`s_1w7hur$#z`1&Fk-4K_m`s~B*Foo06E$1?w-Gvzw$MUIF zJnA%4so|&UqLgYa((hp)hNXz8g$dA||CD^nu;nMZCFU9K>q$ zsBHYKJIvJB^r>do={+yD(rSeWjc5MXlLCHmKU7-TYw$+WTekYvIaXeA)IgWMI;}m^ zxghJn-gQeg+ZeSMRMG8<`U@J|p1J%V8rHzm!rmyizZxpM0M5676+FJ#UV4MTjc&g> zMC#mTYq7)ES#0gI6Bat`D=qM~7r}1W?)S~8ciG!*rwg;zT@oyh?@T-R4kTZv`9{}V zU-~iMVzUKL25`t0faEt|<_x8N?()yMF6{%V@u-KBgIC$6vryddlL4ZLN&NeKZztvr zixvwHJJ6hbV4HJ~@324hl^a1X;y2T%u~W;OpVY+@G;;d4bmA8n#m-FPw3N^UYKeIo z={#NHFTH*qb9hl%JJ2v{S}&oqxkI%O=pnna6dWpD80=%A)QNRX%fWWV+{@eZG#GxJdC>8>JI5|Sl@#)f!T{KL*3UCW!0&}Egvrg z4i;OltN=dQzkhhlBBdenKsP+J1Yx4sY{$u40%5TDZzsdTzm49pvKxu1acO1HP3%5h zIC?m=%k9pTSEsQ$P)cK`-v@vO?re*5ROkX&!h@a=rI>YeN$O2qC~?c+HqeA ztR469=~>@>W2`~VFR$)o4tbs5uS=g8crkB}I~xi>cmdW@l4 zMg?w?e*Qh{-hQaWdOFBlIk!#9EYu)t8!j1IX4a1zQtUo8)D>sb3lPT{h8NIBj`YOk zl^04x7+PhfvDqmgrQ6K2P4|AOw`i`;%qd&j5N_1VE)@B;(|W`gN2d8A?;{*vl+#Fi zpb|2!t&iK>VgI4(#$r03w|`i)LKil8;e2(<{R?Ki4CD9^o%n`pDD8|_7tU#=G%*9K zI*~g9Po;!BJExb~Rx@S4wc}-x&W8N4`r`>jzu%uq4zVyhnp~kI90_=EZ5yZ-Vjjzb zO`ZGzWKESZL3ny550z37%-gv0r~p68IV<3|e~hMg39!{@!5iB2Lf0GH=WDOJ&y82y z^i+)aev6@heWrQ-Pe&8Xlm1gNv4nFOZTLoTc}|-wa=0&kF=p^Qs;*d@Ml8T+UqQze z+qY1Bm7V2PJ|*70ZN7NZ7+u&l(l?e0#=NM(RoT3^!8I?hO=ed^C24on==18)b%(2E zqK~HQ<~lzfmlR0`3?tjLO;0ug-^xzCn*L*Ef5-Uf1KVfx*95295df}#M9eF=5YoB| z?|Ovmi*&+@I;*ali^ecle>zL_+sT}99;Q7zSSj$?g%7-JQ-9&yUa~{4*7lj%!#ca8 zcTDM|$~pt862m8n`c2ms~edlpym-e(&%04&UfFKtbAz$o+wHtX~5>qve`}S^r?)0~g z$|>cxzx012uq96o(>0|o&nYmVP~l4+mkWIxscXVBeF%Sc^DvH7bTUIqYN0h}ikT`Y znZBxNz08Ws7D^5i?1w=?K1Tf_W##QW5=WZ%8T&BM(&e8n z{fidJtsy|YrI?`XAyq=Me4t0*1-B_!__2#ZulXnB)F6S*PvWG5EDRSxt0TYU0!jb`R&Ct$rOYrJ_#vF0}4y$nN47^}X8PxQtm#28du#T)uOJ z5Qzdqb+AEO0K~ExRUglCm0hIz_!LG+T)8sJm%>DLnR!`oJ9Fm3&t$d3^uJ9$@Z=;t z&YGba{E`a2#$5^j`+DJU@x7mp^W zCv@uF>!s*Q zA}q&)V(=T_6X%!+q-+9I%CvOr3g`8ku!}!)``miMEHhI|bS5Q8x8~g?+bVo$XD{kG zSCth9CCBR=K$0*JArb&Z=VrCe z7Qy1Ee!<2S3CR!xxAX;6dF_grq22E!v#vN3lN+_grPI3NX>%)0)HZ)!I^zgH8Wo8 zI}c9{l7q2XfEQ&wA@WC?eBE7uX&$p>m(GidIdqz4ukdjR|9V-Y!+H{D5@s-&2y$m^LD2-}Qp|`WnZn zSPs$Z^~1tdxKU2Y=UeJYL*{~ki8Chu>T&j|<82Qn^H7_lD0~hN-+HO@Qa@m3(&nQ? zY0^-40S!cP3`k!FP)92aSoZ=WzEeS^$!^_W(!Q=2QG}H{>msJb`HmxD327qV2(7*V z=k)hQarC-~S3wNtRUaY|zV}p~RrUu_w{E@PUEW;ab3GNJyL>BUwM%xN3+oavb0I6Ct?oK zZWO#af8q5X*Y+pJAGQ2@OFUQ6zSKz+E`S$aOdzw`L5zc&k8(04&yoRD=Qpqi&Nbzl zbkr#CYIt4nm0Rny6+}8)UB;ffMhL>}rcrEQls{Tk!> zs^)EV=e?$9<*qLAS$h(n7wqr)npZ8plHMdRa0-G{+9mf~;9$*tOAvAHU9KtR3iRh7 z5b34U-6j7yj&z6Bd8g`$36eX(1NzlXo&sd@@M>sj3^fS#l$R28)Tq%g@f_NKna)7~@orkw@-1 z$_MB3yhK)CQ=mf&zJy+*(N8;>_)fxGU*@QsFvG@w}k3iWdI~X zJilgu5Sg3Xio%2*e%xVl_ewmx1ZdSCchfMu>%7V^+&0LD|Kp$4%An+xRa3&I%SIOy zI;$98dIZ5z+-UDZ)muHvl@v@U1GYeg7+j^6q|hT2G+(aF;3C6kFjefaD3!1(=_Slg zJ!=LuPc?|3EMjfa9#O-(#`S-$FleC~ykagZ@Wyf5e-cptAT^?LOt+c21i#d%3S0Wb zOJ8bbMt0QbG=O`WYt#!tb$jMic_+z!Oq*6i5>xdo#QM1?-Cj`l%9uX4M1QhV)rYnG zgogp(R43dTfGIvAVp&K}2JD;-JcZ-xCtvO^Qez+7$fsaCxOh?nD#j3-ZpCgWxXHd) znZHBnRMYD!vG-dFW{g1?<$B-e4*z5j5-5a51tHXrI!8nB84V4!39Svk+u3uUD2as^ z5c45!=Y-1bc^mU3h{*?^pj1LZ0H$_M#$r%Ud44ulx(C1M;N3FhDtNQ#x5>0iP5Ytg5)A_sru7BV+w@+E}tLk zogb6e-ZvPIJATkET=xojh}kGg>2Cw|s>1B(q1yK?we;&ER2h@^3-7n{bV5F;fBK}! z;_148YUQAoF{l*^s`b{8R`K*M^PsFNKoVf!B?i!J-Gl<*&u$lU31U417RfbOV8Z@T zVSm6g3Z+jK@vfV=RJ|iGQLn`riDE_xeG8A3`Bus$xMAPQ@d+c(aN{NJmlTNj9Eb({ zf~P*>e(uE02Qn)t#D8*paxZlgS9zSVGrifeo$IajY1>W!>o0fP#5Mn{P(Eb@Z`uP7 zkfPvUMtT$TL;;4ZHQQ-EXq#G8HJcY9wGxP4E!Fp~Tout-)Zo#zV#U^BRo>MVceu!8 zE^2C9s3_T@UWlyZLKh_vnF}d+5XbgXLYUnTD%g8f5t%w&J8|I^fx^06wg493juRbwBn;5bf$hSOoE41%OM)z?k~OJ!G`;BVI5Z# zJyOifKu{ZH3;R>dUCEa02bF&iU;Um8MI3qhNU30LX1_j0o7!pi3xAaQtaZ2IoeEI96kEXyRuE>XppIXmT_j*rJ9^YXRJ+*q$Sis_<6Da6R z#)xY3+FQ=>WJ#hp9&K|G;lsFl1>fo+rzR*{dbaG1@A9*Q&?)AaTxn1gMHpbXGE!=_ z`l8AQ^?;9SpXT_Sv;VTAH?`}?O&ni7JSQJ)4b|$K;o(w;6M0<@m|ctMc#uTVdIf88maEz++!HFv(Tuq6ajxk+{3+@wgy4Ft1ZF%4f^P{2BuPtH|7`98h42;;~kt?WXU4s zZ2XO}V`dDoBUvV}J)4F;xTCWrJxFc#?cs<)b7HdOI@>*c<~#ITRy-FQba+ z3>dZB$wlFQzQ*{L<)}q|}Sfr*6yEspG9zSGf@MtWIaxZ>Eo&o2iUVmqQeXQOq=K4x7J>uR#MMzm= zhgL&~_7UE72T-r>WXo#z7HTH1I0LZmbnY9|gYxv*?(~&ZcH~PMv>93)Bfaq;bOgzBD{bBfO@Ra;|kgS`~6}kRhrnbG2o(HA7gVGWZ zoO-G`)m4(JH+LgQii)~S&CD%bI??{WmT+{ap?77E*b#nHi}{(~735h1MjV-Oy6w+Onc1>2NuT z2I_|LNRvGMD`R?6YU{)pP_-5C7!iD+ZdjyJ4sdsD24FO)t0%YGeaN6_BUoYt|2K-N z*dLuL$&tKPB6}J=g*|=veb-rqcYCylUx!!G&Dg~c1)%YY&o&8+O6(H~p{JYMl%)Kk z9v^M`d~-BWgE>b}%3eyAC`B+FI>ufIrAUb_K2vV4rTVh$4T>&3eLzm#u)bAW_ebrU zI_vR_RP;V4!<9(apAq+kvUM@LzP-MkdZg^8Xs-`uV5ut`E6X^Ao$zB1oX%#?RjBaIoe;FqZ9sKhb&H?B-tHd z+8t!-G|Z4AsgCwk)hgFY-~BCm6-jyJNw#AoLl)Vbdg@({{?6M5?_&Wtg`PM7hn~8E ze3(f4k9EUz-x`6BfsS)-+Xn`UVD21{DdYISgeogIK`LtJ3e~k^yEsY{%Vm6eYE)O& zOVz0dC+(JgES3#~6RNy-{+r1ezuIH^S0V)fCnzjFdWnhi;nKZy6#&ecTTOLo`FOHE1sI-GCts`uxUCH>7E z%pRStYdoK{ff_C!Qig~5s11#E126(mR_d*)P~*W>fdT@;t|;&^gtX-lygr{?TjKhm zYVDf6s+)+NaKGldEeHPyo9%vIDSqN6uZ1-d@nRT8D+H6^rWACt%*(y zf2BnQW$k?nuPt-eX%qEmyyy4+iATU!u^|`u+P{aJH8;8k^wx}$GO(}fkCq^9uwy>x zxQXk)li&_+EfdPKp&#_|{JlhWm<`Dw-BaO8!e4@$k6-%?ad@ zd#|(`CB^VjbG2fZkD0*8W@Bt5Ij+}gnRn{rM{T@j?NR#j`(sV!fo-R+5%ad6cMbaz z5-@b`OQ@|Ugi3wOR~GJUhCxA`>DmW77iT|HU~m)Ga@tl&KC#&=B8melMRDB;4FC+i zjRvcb#(s`1b=A+r|DJ^Dsmg@+=DKki=>pyH{s4CfPFOF3={##dItR7lfvkA#H?#mt z`n7`932~|pbtm)fBMNt5r?oxQdQF1Hy0Lbty5BSV=;llyyscZWoD5jV0AQc_7-TlW z^$r2}%3_9*PE$CVt`1?y5}hKPM0eJD&sjClt-tB1j(3QO#lZ#MvX2b-9|OT1%c?w+nCr6Wr+hkIpaG{=`HRws zTTcdm{=`9f_45u0rn@MUVuTKs2h&z)y4DW4?@C}~N_C22Gxw5vDOc@$lB$W>;>LvS zrVh{kE1EZ5Tlv&+O!*S^{*4SDueodW&T@NLa66^^p*Tzt=SZ$u`YT`kudC>Fr1!WW=6&jYg`j@0+c~>|KguQwM-JG~ zt0ogPgIq*RiVr@g!P)?#qI~*ys-#50DW3p@Zj~I~l6(AH++Ixri3c~P49034CC7Sg zLv_c+kR+%(TivdsRWf4;8BLzU4eN4VT5bu8^7V2$y~a6}_#*yhc$Eb?Q7M>S;`;Ke zKzA92K;m?{zbhatnN7xXpM5Mz*RObdKwEwW^h9}oE&~=!CE%a7(u4LvB|D|QI!3;M z?hV&UQjLwY9-0f4J{aMS?~Ny`jl<0%XXUH?3{@-I#w^OmiuMkU>wIe3zG}B6aPn)q z{`U$Muzb2C%N&4AS=>xE8$!{6!&D;EH&hIfBb?x-bgl}c(L!PQl>FpL;V2+WMV;3(pcrVxb| znc?(&c|Av8XT!S?XJUc4+tT1Rn&}7;bEE?6{{_6d(X{o1S%0ufj#kLM{^xcN4tL=# z_k;|RmUtVUZZvgpd0O#AlE42&dqL|?dz~F!#yM|O1a)s|d6)aS=x1kbZa=5|FRMuz z#K^vSN>7!3lRkyM=Kyy;<;@%{JRkFSQ>ojzwYHcm-FLNek?yt3;*?>Sp6-66M{DPo z1WAbAh%CT8as;=%(Pvu~>z=^1tYCH2g!b9~SXWtR=`ICU*P<343d+BkS{4VGdCfj0 zayi)y3d)2=MlbR}ykY`QUDkG$+7Nm$-qmLtOs$A55T6H9w)|H~`ZO|WE92dNee82` zoZ(i+T$ow@#DM-xCCVfA0jJ0#S6f^Qb81`;6eRhOD~WvSBwfjz_~-*ebJhAkQ^%JI z8nRWPn)^)g&SM1?%J^vZS+%C(8%A^}Ch{f2YUIxAzohaedG0K$%ai%l!5^76XpaB< zqZ07iO8}|421M&}`I!`oexhg@bEBHJW71jDh1kSEWpKC|lL_*RBV}zyAS+{Snx=T0hp2{JJZrUvVI9Q@8ORMew0qwm3H0Y$7uv13Ft*Pz zcD2AI^ZoVJAHS<^lUNu4kcR@Ym%{CVtdhXZ7|!OCeFuq60G5%Bn#^K^GdlCVQR#@! z_kb~J_Lzb(Mbn#7q`VRXPxJSyiJ4>=VOoJ3Q810v*hb&6pB32Fn|SLUpKd9pQi}PX zLith?_ADcU#3jJDu2Gj04x#bEg0;HiyFw@N6O1JwiR(8R2+VS!Pb~mR4%h=QrwlO8 z=#U!{qOl+}+mXgc!nx2&RswY&%+nn5T_(=40yA1v8?ULpNisd;r?#`plpICh%cmE{ z)A!4fqKU0RR2>r;avc%2ngMfS!6I2O-{odo6FizoShLS&Vmxto8GNr;oszhGicYMA zp%cQA=u(7>6tRMlw#5Oyb{yo-Iz=d=uOYNbW-|sI_GSO_Nbd_tN3E#eofpFeKb)M`-2H8VIJG9caXk(^hfB;V@1@{PV1!|L*c%z{iX2-l!#q-81{HWy?ukV< zsALEJCF0S(g!guY)sBwT$ipFi2NOBS(^`ZCSp^1w9NEzElaRCc+;$Aig9Ul8&r!rM zyaKXq@uS@vDc?;k?~}_eReJIDk~>l=8R9 z5$hEQQwHq%A4pjy!TmY9Qv}?~4>isJ{v-efpK5+d;N!8tn%}_N8^XZj1RoiI6BBSx z@c+&dzDPtjf2CR%;`(0TT`%IKi8)V^^>5^1qjJoETCx#Pn!u5(h>k6I$M+-wg zu8RAd4fy@WBfekxd?QA=DQ5Oh&3Yp1`4C=J2K?Jy?)qtqqg(1ICr3;#uNZ0iSB68U z6+Br+K8o>r{v^e#GZ>Q1ZWCmFI%R%u}S<~L!py_JG2J4<9AwzZ6)=iMvOV}DgfjrH2AgEF1b5hwf;DyNUBR?G1=Lo)8-ki|)(}kpD04dqm`%Qe-tgk*<`=@Cbyxr8*NBB$x2Y2LDhU}Ey z#7~QHAH+*I$Qc|Kv#pKmCn>l-Ii_2InIbl8a|qwK1fYlTlGS|3f^cAy-#iz)N)YD| zcMyKl@60Wr=j7n`K7^Zduy&KC=%Ld!$m%}{fh={-;;E2A0@KB6=ap@;udj%aL>^K@ zt;ye-AFq}(rxx=Zeca(yjykDO0Xtp?BPkFBS=V|-?FA;xgbR7o5X%EV@L@Ys(aYbM zX24w;B3AGBNL!f?8d5S0B__%DEi^ttRtop$*zILM;l2{`*IO`#JmW;9^$!crCu=>k zQJb6qyNi~M|0gBP19$|75EA|Z9&`JfqVQ^)pV?2tU+zY8GR`TX|LU_hoqECGx7YqQ z5&p`q6`EQdEF95h!9tu()v;=Me*&}8O{?x`vs%s4-qSbtu8)aSpJ_XFJX*aF?z&Zm zG?Byq$>9Iw@a8XsxuEVos;n_s7WueDj+zAuXw5QE@3sy5Qrl~Thuy|GTIK-dxDhVS?IP}>81s@b{)AHh z(x(316y{9~ftU#5S)jIjq@RoZ9bxO2)$E&Bqlq!{-pMh~HzE>+|xY%dP)1Kn2hy?GxT*Tq=U`KLJ2bM zZC4mgdK?6~2-$&ukmwh53d&%;hulxK&!Ymi#G4orBR3en+2RX@e}&yt4e6_U!=9=3 zv7H~o<(&faDqq8L?UILcSG-PFBYU(zH`Xbo>7))`j-@R@fz6;U7o;elh12h@+r*<2 zrEPe*+uJL@hx_1nfxs_Wf20HlDPfUKP?HXa>w$ge3IAr9@175AS#byZU;m0{_%nmJ zmsa(%riEb|c0hr>A|@=;u(1G0mXEvuL}nXr+iY|6TN#H2jDmbQKL6t9m*YUhk$*&J zxz(Uaffn(HG^LZP|5^TR0@wLOAD|+)NVxIMitW&;Et#$=hg_}3(n{RAHup{yK1Byz zE6L)Z+2>Hc>yhQ%t?mp&%U;lv1^xSg3T{IBNp%y+@XEAxI+7%P>7brC0rhv9u=#tC zd)pSH_c~c`{F6Q!D)j=(0MTRmYqE6{%9g|k4FhGhxY#f;hHR$(Kk4tIvujQj>$?2o zJ1<{ediujvru!;x~CXYz7PV@9p1zC0`nPg;!NFs5a&Z}?5_jMC}b`w$vr znpDCk9<-WS-PE^c%k903hVzFdgw0U;pVrInw@b7;E>AaacQ6gzXqWP(x^rSGHTvex z$%UWCks+1V>lYS(*P(p6;oA^zhaA|e_2FpKsm*t-*If752lr6pnAui$z|eT}2Ho23 zJpAR~+vR}6RLVge$E1E>V~>)Gjx+Y9ec~g{v6xp9#|wdLg6Q|}NOJI=X9tdDk8WCu z|65$`vSY5%H9hI}DVI0@yP7o-SggOKm%1uqcentfuB=%(_#ZE>0Iy|##JG$q(o6~J zM2yz{Hq%Dbt?Yy01Gq#Vl}*IhT&2zE8ib~!2Ngzepp1!(@+o0GW_}*yO6sUr)Iz=L z%vmKWF}k59pFFor=FG{AGo&>FbB9Y`$tLOy{k1LXofj4Hb>isuS`&x6nU4yW3s!8? zLn)S2AtE!Jfs%;A3-#;r!!Z_pMcIW=jxn1F+aEd7SABVY))Klb%c2;h%eE&%Ezif0 z)rs>PKCIcT@z7K!9lbU2>Q2eW&$dbRuE@3N^?WvX=;x4G6@;Y=tFuDdgwR?So#pnO z+xJ1e4e#x~v>+%Fsln3o$Zm@BOB$M)`;s;y6}}E7Q=L@<8hAq6yBrPI2~or&W5cn` zuk`8W(^p(wj&(mObs1HB6@Ob?D0lz%oE`32Hf&x~Y?@3jDpY2$jJ!$94r9T;BWOMf z63Qup^d}pLOr+;L7cMj*#dc}%9{ZES#+O8Yf*p7tkD zncOMqFEs6tp^cJ-qziTX{OyfQQpPHt94_w|sS#0asIc&wow*8q=cJ(S9=E$^RA% zg%$B7S*AKmY7u#iGY48MKIkI5vd+VELb!m#!-RXfjxwLRJ|4nL2*3|znv}y1Ca86u zA=)ScM@Dj9OJh-Mg2rBsO)+d--_MH#(Vnj)b00obT>9!Zae3lOhevtfW8Ch)?1P(J zN^S=hTUj2i%{R9p*XC>Df5#R(i5Au~^cm<@xd0bH9y_GEXm%Q_{Z`tA6LP3aMpI|r z2@C_Qhls3nL$NPQArbAnPK1TUP`%OWMa4S@u1{# zIqRdck4#9eZ}K5laJRc|;C{%q_k|xDFk5SNly#--2E;hG14|Qn&4isthsaYls|0(^ zErpflDB|`0ayE{d(r)ghV0Nly_DW`EU2KkY+xAF$9k#`m?6>CXJ4Ow@`V@=LHfN-n zF1u$_ohNtqC-14))8|2I0@QM@z)9%Nl%~l`6`L6F{GtJ5=m#sp;4YYrxJz@IQROOS z;(EhM@R=|2>6FLHkL_2c`xK~hw7wC>SC#Io-KXc-pz3*WK@Wa~4cKntLE$6dy<~l@k33=q;IJ$SgUq)-GI(<1cJf$b^l+F`Ym{Njk{YH4W0^3f zOp%$`4#@Z5r#I=iqlPX#tP6>>SLvAz5m$p(9;$LKj^5}jSH>TY2Etk za&%lUKb*G*6^3uhMY>9;hZEZ%y$iKc$T=F!NpI2rWzIxdN{$V3wgIO*H+f9)0IzVl zzOXwGwMuyQ>53=mcM2b-?o`vk>h3^Oh>tX;X{a4}#`snDBh7xumq8PK$`5K(Z$$lG zF;Vcq{V=^pd)eQfM*PJ2g?DSlvGS~j9lYjd1FqGRU|^+G<3_*#4bPyRFIF0fMwiU1SNtjSyu@8oL>h2w zoRq9|PBWG$;qdDL?c-hp5Jmb~d7Yf6zNtc>ntoxe2d@D-HhxQY`EVRKr0uC81u$f; z{=7K~CZmEaAB_x@7#6VS&r7a0#zTDmsgQS(ekV07cWzodrTH7eCFjmIVB7k@bI}k{ zB&qvVq3b!BdD1N|)Ul4q)v;hiV2T!?_yffs|6JoA6s@bb{Rw(o%iuII7p6nxkz1v( zG5Oc%XNA7sX0mlZY6nX8z4?5T=A)l>he{Y5=+0Qw*3Z}+7^7YTs9VZ&e=l?^{aWA| z_EQL?X|DImerq&+2TVVg3m-`DLNY8Z4tgYGSrR@w#V#!Om<<7EQfxTue3nOe>Cv_zKs(K^rzV4ugLPYJyk{q3Hxg$ zJ+m`Ds~LqVT$H=xt_v&61Ujx~kJ(GcFr46t^V?dcK@ApoXc}g>z)jljjQy6$B|9z0 zg%Q?rLdn;Su&ZTHy?&PQ#?Jeu?Cm=G^?;OzkC-lttALdj_!>thr)A%F9k?En$j_dcK2q|4U`H=2DyjprFA#OBqVtTmiEuafbnzzy*yc zM6aU`FKfKbZ3~Aa?(k(?=JhP0-mUo3GvoZR`Bj?|M zH{R7~II&C00qqpm8?AewNEokr4^^|!>HhRF;U{)wjU| z$#!ntjxysLUQ0TqB)-sQLF-@(;ipL3GxN2kmA6(P*JmO*`}5(nqx*=qYTdxPS=2fu z%wUpbRt4&@9e8NjHkBylG;!YvaAm4@hwQyF=wv3z%b<;`jRrAFpdCkJd;z+Z26GBJ z@riskWoZNcw!QuFAiT?nU_Po^LH^&|cbKJ7>7hcXLO*^elF9fOqJ?bx+25IG$-8}+dVyzt=k@Jh zs$DVN4LgATIA5PVlpu;>{~n30*|^Yq0F|0avTQ*uUqg97)=}6rW21^DmA6vz z6GxEi(Kl1sMn8^V+pga#By56$Nmz)Z!0jS2jvAii4@XigT`$;9-H8Y)o?1c}El zkQT=d?$$oz_k?x2W75`kzi_|kdHhLRbI`;dpp?ue2fl)jezB~}b2 zGd7qp&({v|J2z&d+lbX$tQs9&{UhAAP`kAzQ>d4X+QBX~#0vLQg7(O41u1}^>nWr{ z&D%~nXvpJ#GUZ*<9;fdIA%am`2WezvtSM@?*l!%w4F}27-d+NpExP36{#6a!w)U=h^etWU+2@5s&?%$`giNd{N{aMg|w~DKRcqUK;?ru^}QXsdAkXz^# zN@A`)mz$Xx>@PwsPLys8fsD9(w@ldGTu7&%zcdnTE^_#<(?EryVnODsyE&?6@i7r2 zX@%h$T4?3A%L0}pC|+c}8l5s&edYFjSquK1-RgJS1%XM-30fa7Z8ZkXCyCZ>KK)de z)sSZ8GCH^#M!fj=+6Gvgu9n(>BnNwl2Tn z*`uOdBk08$ee}oaNsK`0{iO-M;AT5MY=+gHU43O^t1Mr^>VvIMAOTco~(_pP$Vk z`E@F%Rpf7`$nVOAiyDumdFHc&@)NkqyT!;jF)~@6pJb$SxruvFCRB~TsS2FV_RxKP z8#vj9!|9Kygoca&E6((A2{iDoe$);%7kA7Ot%Rf z`CDpD2|+W<1$psrQU`rDM(r*P|5EnkenN}Y7v7Q1c62scV>(>$z!7V2!(mPuF`33H z1y0X2QtSjJOSky84V`#VF=5&!@8VNc^P8%ycN;B?*s%9Mw)%uQ8(ln!(*Jb3W?kqW zmeAPmSWb||o(1Hw$-si=*qTq)G}t{q#Tv}KIz>QHgeob~VNMy+ix2|=KAoooyZt@hD$ z8WH>u`58xA3z|6Leq+h`!L)s_O=RqL-v?x@`-v#CmcA{OgV#?K#>lRJC%s)VwYE?bP)luKJ!k z&kD%?s)_NFLd*genDKV{k9+1nz=ma&_!0_vQjdIpsqH^wwSJ9Yzl6wDB_FhIegALO zv;}OP6q%Sb6Da03wQ-a4x%Q&hSa!MeD_*X)0b711ux~4VIPu8lcFDac)0t!cGdilT+B%uDmEWV5PDiQjd!Nh_ z?pi=@P$0I*5ztSB?7xogE76~=rxIxSsTAZE=NFsFDTyV{*hj)-8@o$!wn)Vcrh)KZ z3(jqb+f6KgI|5vuQ^%3La1C7T8P_up&JZNL#2SIa667hOf7q@6S#3PgZbM29{$N-6 zyK4LHPmZQ4*LSgzfmr|y5JKiceM^DQ5~%HzYZD14MF~u#Uk@x@c=6&c@7vp8FD_rl z{NtVZU`+~7&7A*rK3~|&=lGNXs^{OG<{pA*Yf`sX&E-AK3v6l#Uw##~>%g%JPe=-&UC{@*`< zzjiP?Zy08VIm;n)%(>0^SR<#Tnj(i(bEqiQ=B$u&D%D6%Ny{loy*KA1jU-7mktk_8 zO3HVi?;o%qUbowBuh;W=UDxA&U8yEB5lDV8Ef6di5)@kMH=O zlU14@6|i8i12;g@ELK)vvVQU^D7oP9$3W-`Gu8FWg<;1Uk1vW{-@PVJrO_q!y9i9~ zfLM#bUID(hf_(ElT+0Rg@_)NUd48{CQy*7P(vIn_PkcEMlRDE4H+`?0^C>&VSKxZM zN%LfWWaCxvB4B+E6Zzk>j86S()0A)FfTS^f=0(jy+K5&hDmA?%%?5%2i}EZdN*W}|T9S4tKj-DdJ7Xl;r%{l0+6c!6O0;qinpj5{FtXQ2fKi+90 z3oK*2I~J(>pjqwe%yK>TUwcC3el<{Q$l~tO7ruBFE;PF&yAafSUjdVC##WFVP;HkZtr{+KZ_$K0{ zWlPF++SB zi(Q}WBf4spIHM@Z&#H?TdBp#qL_BAYnz*Ra#sY%3DxeKA%>(7G_8)%`6 zU=M-8#yR{BW^Ru!8|n+*k0i5zh*FP0to=;g*_YPbjFyX0^C{mjCS9UVug%R}mb+qk zaZXt4*TBH5BLmAYpRIq%Srt+Wc4DA*&7Dbi7z^ZuCa#IoK+=-|0Qk5{lJwQ2$IC6T zTmK|+1@O-q>TgqaX_c#;{^Kj|J9EH1Op55I1(yy$e=KAwTNB{&>8Bg%VHu~pR?;$o z+*x<5UWGbe9a2qqwbN^_%NPugqC;_(WUT?3M|fBo#zwXfFSnbjrB&#RHibE+X?168 z(YQtJLAo^ZQgQZ;{|lpEEh)NS60q|b*2QPH4$8hf=Kv#U>x!)3hNtiI@g06Lb){EN zQ-hg7dj%_*87%WVH%K9++%i;b{V#>;!hKUgd&~C?0S+$%m=#k0sA4@RRw#EdTv`bE z-7q6eI1l<&vL9~uq-JEe%-j@@=^xFn>1t`Z+iCMwm$Mw8dgeFd@dX#r8`JgyeZL9!xykf>lPlK)C z>}*d>?h$q_B9{Ld)si$=J;a7kfev4EyFK ztnOEPWtC}|RC@0D;Czr|y!B4Z@y1u9+myr$ZqWQ54hp(m4Z~9qe=WQs9Uf^tb`OAk zpE-|Y&`!)ELHD{cI7>eyOU-Ba_d_UBo6_m%Zzk8UVRb8J6ElCPyBoxD zJ^9tCr54_Gjt8xJdZ8=?e2$6JV@b=xxo~j71}A)mtn{dynU3Q=gIkc`1X(GFj+l#$ zr+{VrEn7B^f5TdeI79usEEhvZd@?m%eT|Z>6V6sybkD+NveMP_VElsGt>1 zR_L);5g{h3hD@j0CdsHe+Fgne`P8K804Q z5*3lu`QgFG8%zhN{>C-cc#*V9qw%SQXK4?+#8M-fhfcfqUVFJtgJ!8X?vuNo4tUC7 zjpz6%Nr?m07yUsxhJ(=IaWQ+CnyS1dhII zY;lVfM-TU8v-4e4+eL4qF5AgR$+kn_Z-+6c-3N=$K!29pDg0dh)$7&Tlql2A``3*l zqIldT+RL<=L{L_zs&19;WYy%%QB zNA3n}2>`u)BiCqiciDY*TLgrD|S{7P26X+Dn%?sjE= zNI{wmmm%$@oDI+9C8`@f$@csu0S#CSGD8nvf1ZMVjvhd4^XHFV?YPoKTcW!cj(Hb% zDn2}Mrbiv>%WxuV;F1S#-@a|NWv@PMvazeWd3&<;cUWwUW|SPa?2 zrNPgl>D8M(l2i=S8p3?u^FH{Ly%sA!IAB)!b6LMx%zt^|?$--{y5{Abk;^;G+pqFT zq;Nh>af5|eg(S;IjfiFQtx{GsPrUNI0dLrDk7kOXSs70i=J0#E-CQI8R@eX&BOF#Q?f%7=`CNGwD?h z7tpiu4)xx$VvtiVLqW_R*9MX2I4_d9(xh%O8suEM8=(rSdkKA=my;y8!l<~keW}1V zn-Hm#9W?$(cJxwIMxb&d=hP351~HWa_m}@piZEi6=J>aFU&Ibdv`HGmJT#H12Gb&M zT1W4hZSY{@qyi&=ueWfaw@Ov*U@Jkwb*h56zXMRQ3|TFyLH zf5pd{zRiyFJPMP1(ZiRVahW(g$@O_Nlk?_Q)ms_=8=yD%pER@;O;+{IsRaN`PSvPZ z0*7*ZqxlYoCGP{W?3WgUIqDQ&PP4B zrUFY5{bsRg5}VL#LiNFKb(S#r;CiO9H)IPBVmDm6JIrszgQgLJ`eu*nj^mS*Dq42a z4AcYn{ib0S&SC9Rjp-Tv_vjm|bibr`r&9v|B!y1Z5h8Xn@u!G7=_)3!MGEJ59lxIzxD55HHzVy2z&q2U{da&_6Om5``vuz4oLf6~o#1T0KD z8Upk1gh5gQZl-K&)as$~=e!Q5nXiU@86_@rBaOJFB*gZW2a#=r?QI0@6)o~zaT+w` zxmIUUQn2(^JuMXXn*Z9EX0Y}Y(ZKZ!5V2>qh_}9AW*ARO^NXrRiVl3>mCd`lQ=&;N9i8E^jq)dRpGvj zkOeCO8%qW4pmNlK{b#EOagB5=aaJ0yA{R9WZa}*d>C(64^1Eoc!Olz_I&G1LYl0v0 z3sPNutLgdrSA+@_%W3#QK3FSkYXc|| z_VJo!zuQ;CZ8_l)(-8T&o(6C1djieNGtFT7>e)kShQe)>pKoe9U2F6qTi6Y?&>K?W zMk|#cTZTW>>ua3;3Te^Xck7ay!q54w>uFnh*=l6Anw2AnPzQz{e0-532Y}?^@QQlS z-|YGI+#8;YbR{(K*V+I83IH@4JO_|tnX-5RuESj|9WAkW(0u-*E;icmdY+!MtmsBw zE{H%BphVd=IZc*h^XlK}Bx-jV_^NuNK$#CBS{-<)^2GX0I(|Wzq#eDzJV?fwKd}VJ zw_e{UCKY-__g(2y^jZW(V+r)`&Gh#iMLPkw0HjGsRc{@Yx1!nUrP}Is+od~!+0cr8 zF`I>8NsSI>z8%8`Fji+JsqJe+0C(O{sc5FIT)pz^(oqEfvH*byN9TlT7UQbPI%$@~ z9@U>SpC^OA_@teHy*oTtZ4cdBuj3{b)~*248l-D+9mXwI;Wp+7R>Q5_N0Ue^nvz)m zwt`+@@C{{u`Wf_SU`Stz_Ce25&W!5jcSwL#k!r<-K+HFjd+BZerY|;ez=Q0?ZeVnU zjpnjVHC|K3v-8R~6TZJ(#P*_SAmw$of2UwV-jTG<*JQYJ#t%OPFNTxqHwrbPq1+Ie zNfW^VgdasJScH>ZROwmc;7O@!NgNHk7l|_dZ`|GZKS;!O9n=kZ@bAhRO<7!-}Ydse2Z~k z<6S)#T4`RLsno4KRC1b8R1D=`KeSeNc{SCPmS#T*v5WGHuWoqpHMnKNM$G&wSF!D`Fh&=)b(>Fu?YK_1TqlSmb$+l1Y`219E^nAOY|R%+Rx)hu$7!Z7R!#2y=}r)PFsXcrLQ6p!V$8AvzmZ~baC zOQT(~$EriD^mMo3ZPtGrn{2v4?4L~!jc)(kzL7Yw{nH`&*6+8qvlYuZ zir+5;mI#!R1_4HK3v9)xN}!ztzCDfIh~+wgLeng|AXd~$^m?C3V4|!9PWPtAD^FS2 z{IXCDk<|jL(F6p&ZeT@3suocGfXKZGXmj854)m8-0H1+Ga_#kP(k?20oL?uG1sTeu zmgU{_aF71STmn~WP{D_W4%@l6ol(YH6>@9`do0!g8$C#cD`boCjTy1WcmWc8*%U|X zNWb>Oz&0{7vSWX5^M|~d5A^32WWI$SAHqYLHG*}MPMS&@sq8;vnY9K&u!%4!>=n_N z(7rqu4*j05^Z7%Nn4Px1>UJ zsZM4znA>FwX36*5ANhyJ87|KbWrlZzp*N=#G%iRMlW zUGs+2*L-m%|ED5`^@*DSmH%EhEXK(d*j$wH#{T1|eSdBL=6LkO$4+M?M~*IeqE<6ZF2P;e^pj z6m9Ex1N@iMM&X4l$IaDSR#S6Nr570|fBn*rt`jurcWLU`l|Vj$a;uca#ecqM5z%$Q zO;0b}11h@{IiVhk)f*J4ccB4HizbU7Gh~fB%EaDSpt{U za@)X4+ZcXgaA_@A6*x9_A`alB3Z)sffq$22oP;NVaUoLrmbD&ZnTHZ0hKZJukBTt1 zuCXDvLhk3kxD-gXHr~^J{PWlMUP^5U8I6VFg7fz?Qq~L?o(&w4+PX6PJ9_fPk-eGd z#h;(O6peVdqlU)*y8L^pc;??5RlVzg8&2J zoJD&#GRN=g%mGqV2j_ru{8f{siuisd5!#fH4805$TD!@=jVgpG@9^`GDm_Sscc*7& zrqk8s$duG7MSahA7+Se|HC8jJ?mE`N@ng4E5i;(2o>P0ghkXM}r^7FASSWk*S|sMrpP_ZR1EQ z_ElE*?;7GZXh=jU!xbS#V1!y9ARgig=1ape?;Y!SmwR%=>Tuy7%g%)=&VkfV6Ee3! zr$_}f@XBh=3%l>;3jI?Fe}4BdxjYkbLLWL5*`ZMIxtzt{qw)1$M+mh#`HVqx&3n zqzmCw!HWO(#Cm64%Qgj#?E7^ZCnh;a2i;i58}&BpPCb^e7yB_zy_Po{`#x-?XJlsV|L-mWElQmK-q2c%El$`S- z!5GflkS}R!1`qMW?z0{)hH&Z zvBz%M|H846S%=eu#tuI_6m6FT`F~yx>;*1wH?N*m`{$g7gd2!JQsDz>rD2!@*`Dd5 zoI5Y^Gr{*@ilnpvF{yVb3-@D~_o}XoGDsB&-Qd{E3UBB8G=z`zWXgBFzRJD(&_jw5 zyHr4ey_cr5BjTce(?R`(nP37Q3|$2|k$0+OYdg}l@t1== zgHvT6iF~MRncOg~>yeLGQd=HMUs)jPrd*NV`|H@9!K1llYSno)fBIX%CwD%(wAOsU z2H3B*##=J3RGvIEQ<(`?9i-*!u~i<6q>o)vhi%`q+_w)97~{8rB8US@P{!Fq_%xNH z21DpB(o~v4V*9g;hnQfw5O(r@HSIzA=-5;PX?0dgPXfJ`^Pze^Mh8`Vx>Z(L((cs4 zct*-THRv7bO%;!B#G*XC(@b|*AB~f8ndJIi#Y;I{8AZwO(VU?+W^Tpj*PYwZiyQGh zpH$$CLAj^x@c62*4K%jdz5F9?qe%uEJ1kATeyZPcIShb^t{*k03OMQiO&O2Y7wI_!;DVqydGt zN!6&*O7A3-gw_uT+=+K>Q_q)sRK+~$Sb@Q=znhxR{Jpr%W;u)^0^eoB&C}%eu|uUD z-XA>%9RQ&C-9b@LRT2G%j|I%nhX{3BSHCUC%Gc+jr+Yw!CIUx&AQd^z2J4B@GOWKa z9p^*WgFi-{ZV^iTD{966v*=Y8X4YI5^+E!ts}vMNx7<^?aoFtEPX%qe%Gz=ecKT=i z_P0DMmm45p>tMg_2yLUtf&w&nlY!bnDnPRwikGU(L{6wV;9@j0@8ZoJsl%?liQjFN_tsPw9dJ0D!5@A$r%Jnu+`A^p1+?6yEr2DdSUJ z7qRifB2&5^$5D^LkrvWKHZ*~3Hh!;;UGxjGOI2wzMY?KD9h;S)K~Rs2-85W%!-2QY zZz{YNx*>N1epLUgPtO9xH0BRVAuuQKp^p{p)(l?P6;kUOvWejIe6x6@!hgUw^I%1f z>JL4(&FRbNooFYu?wcSC6F5aG5lLCI*(6h^xm|@{Re#iFSzVn$2JurBT8SHmdq$A~ z)f#daf!}{J)V((E*mtMQ%0-8TuOGfJNuNy{?CZglNU9BZ?xrG%1fwdUE%`JTQ&8D$55>^L;Bm zq8s&}>2Z|8D;3`4FPCGNyXec8Ms9w0tNfWq?g&#`=UmZ;fR{N(y_sSn0GjRLJ#1_Fnx^JoQj6?vXbV#NLm7|k|M}o->HDP01u=#C6YE@Q7KYa z45gFXK`O$Aqq(l8`aK}od{qS+!rOyXJwpuT4DXpyJgY8WUir64;*Wyl_#nCTN&=rw zOj+T%bLL#JcamnebfbxOVZ>0n!pN`!cc#VJ$a)-2ilu|3Vn`Dp6;-jaHf48z+Qp^5 zr@12w-q~s$AYq+TMARqaE;ym zOO-@;meI-_#S^TKh%x=ovKzL{#7hKNJO>X3AsuP^u^bub3~rirD1{3TMNXyfJG?5G zn(zId>-dAsJ#vYU*7w#1MsaAtPuWqt$38=uJDUx4jmd>?1_AOMi2PKc? zC8VnpXU`MPjuMp~E42zDU7y`aO;f1ekTH=fI0@rD;l+{e*UmT0Dtl$^?w#HJt`BS? zUKn|A^RIEfPBY@o%3f%U>H`B>&4`THm*y{SBI=EefXHK?DKcaArk`aqImC&>))OOE zt#0s5@zybql_%+ygEMw?S^Hlga1CFqr6E1m0M=)NiF_!7hC0ne)=*YtjUO61Vq@ab zVhT!@gNK7;z;rD7JGO%_RRLfX!f?H89UI&^bIP`N&}|A!*!MLOq)2*jLH`Q(NBh@T zq+UEe&JgEoc+Il_>X9IJlp7GJz?iOr8EL8BJGn&N8SLB9qt0ZRniu;R*Qxt~UMCBI5(blyvl@9t=+MseLg4x>w zxwcIT4)37K(aT~Etc&(}12D{2ieiy$wU>fxxO4c92ul2NIzC`=|Dr;v<};4U0gChx z7x{vzk;DaGVmgd|bZC?0yNlt8c?eko&H5}(mQKfv)8y18|17;qzSLC_>L(vL-23ft zH$=ocluyw!{eEtKep58k`3hLy-8`=W>=bj}<#~XM7r24z`DQxIH94_CD~^03k&NZQ zhWKu0HkhgeF1cJlJgrV{3XAmHrd(9144qY?#VNPbNmZP!)rrbO>T>&HmCC}r3PEPu zIc6C%`?vm-eYgFeL&9U%Z(HyRyM8|Pd1?ss43yhF-o=yIUYW)%p_B4UY=s=#38_8s zAEBZdhL?e_X8h-H)bd2WubWVHIePDz#Ji0gYw7f_@mvfNAUDXV%g3uzm55q5!w4CQ;rg0UVV$5IWa3$jiZiVg>|^-qc5b^J|NyJNdVNcR^qV;f+@ zfW+NBUw7{%?D6uaqwrm|W&4*6jCe+hMa7 zVRJy8Ottj7Eg-RFh^Oul`a$9JGH=^w-izn&=+Vh3{daN&%?<*kP<6#v4mDh0ZDkPK zGhlIdz*+&H&J}!;W!rjZ+LC!{I!u+-7ia$59U=Rr=R&@`yEFdX4flpMZ`WRO_SowLIL?|^=)kfR!C|gBjA45*)xp1GhLgsv;nChcK&JF;hioM z`g~{&MYWZp`feuZA`_Rchfj}sk*!BZRO%+j<4Iw7cu)>%{CWoq-Mj%HJD8{r?%8`Z zWJ5VxqMmZu=N6f$b_%+en_I<|_BAZXV`-x&w$Ge!2`uX$m&JbKDV+P4~^{O zc~}fsl>*BB4N7W1wf^f&#<5mxOVk(0R=^eh&547kQB@>@}aD@$LY=|;vE#U+(RD$SwveB)Ste4Cq zaX!-T&S}In>$Du$2?FJ4cFO3G@OquP2zt(`W*O{vU6VCkocVQ=&Yd!qx+i66GfZqF z7d8k_bW7A1aiJe)R4+B;_l)5`RcSTqClv7am=qs7*&4DIjN3+;t$;q zTW$v_(|k#ua{-Z*BT-CLGk`4;;fk2JM3GeR4Ok2XsvzRdaxhd{eIaB%0H;bJ=aW!lm8#<+Aov;aK*|QHdHe0* z7H$|%4!BroO;KZxcs@Qevmr3H{AA^jZTF1Rd>_=Fn_%NFx;p1B_czWoHM`a8mG(H7 zT%DlqQQ2l32KZOLbqrp9_j_**U9)zk-MENcB9a*qpj8Dj3Cn`pD3$h zUW%NGnBKB)FFF(&VI&t5aG`{7p z$I$)kyRRN9hRM_bV1_gz*nhLm0A6Y_9~3PilK2B0AjQV*%oH8QEtgdiil+7$|)PaT=xhf9m1NPD+0&66ib|1s%DEaHnk(HMs#Qa9oKn~F|}p%o{B^g z8c99PvR+u1Hu~CrZRE@n{qAWldmR{#0Pe*d!jv&F=CkA`dfTr1gw5)J23ieVhyDB5N zshc$5%_6Bi6qNou%p2fiz?BDH_T$h0J$rfjvt>2iUb3woOs z{L~4F8-k*fGYUmBazn=QW$N;Yf~4!3CQril3nVAd;zl#GzJZy)<}H2ik380+ziWti zd!=${WXtq!UxoNe#rT)gZJn>$B4e!&DxO^*{7ZlImrgMf?e5nEU$yVzNBh#Fnhm~c z)T%!|rOuvwgu9g4;q`CM_l@=h4K!Z)e)OX3K2;@ex_mC3R0pDP>6cv@%)8OjwaMQm z4yijPy%?@IR|$PB8Qm)CV$;Ks#hdhMcuF2)cn?brjL*g9bcCD|wHTUA|0Z=_(W9vA zG!_4!>^dl}@dtq9b1Xv>jE| zK9@}*rz-xMmJJ8o4s8zq@v-k*%gtR~Dba5q{=IfAsyzl#5qL8tdEdHf-LDV0YyYJv z7`hh-5AWXc`F@qltG09M^!O#bImQ}VbN$Nkhe;puCv znNR#7BR~n7g)qChZklT_z%WyF%)^-D&*j~i#aPRhthifv>c#ch+YB;9I{Ocf!d=q6=KBGAihN$#tHkxR>);zTASd z(wA%SlAVwzr@P7mEBaUWKTE)>X1d7-5xZ3Y~0uj_B4Ist0`H@#B)N^hwucS z21qmHyyc6*o)?>H**lPjTM#`<+SLWJ(`}Q4XSrr0#Qnq6;`d)GHh0d&zcyO%Y(X7g z(&;#72*y-u^XAm`bP$W{1>umOdt@qCK$(2>KMKA4H9{m}y7eD-_`k9aIdC9P><_v+6 zi8U_gr(xYvbHOq;p{px|2=ip~G525a9i@Q}8IA}$=BZ+|Hy=^!#X3;oOYxx6Eqz&7 zZMOh>>*rDdc9oxh_@CnymZ~QyH%mi)jLYFkViYld4osmez_)3X+2nL)FwHfhtWMs}4V%x#zcvw~VIa0U^`sp5FAJ5~Vx(%zYmZb4V|YTrY&75z_f?FGn{Q?IX{bYG3vWKq~b_ z4alW%Ihq84>b2t6U5;BCFWt~&zjn{c{kh}5=U3^i7rt+7I~_yMJt~~tc^9PGlKDZ| zTe20rSI+e-yBK+ZGC&-Gg#8rWc(5zwo!o7Hzj4%P6XbWiqK+24;p=Q3oQFFt&w2}a zcO7?nH4RLu12B3_Fg!&74J-#Z(Ch-hwMTJCEJ@Tca)jCWz7Lp+?<1kC=KrqK>q=5W#}5VR>U_22=Y9El?7m2D-d5z=+2PaL;xE-TK>UaZ+Ww5Zs#pnW0xR_

zSr7MAFl@n-T$AKt`EVugYN?az`Ob5@H@&?K)b(vKB>MVE(1d?)= z;!zvcV$%LDr=_PU_UECXy;;>4i_=uP4mqw`W}Pl>fvJD->#h)&vIHf zer_3JVc?>t6DoJPUr%eJ-}KG6cIbXb!j_2)WUb5*l*rX6{0=#m+C!QRp0;uqblhKf ze|*GqB_Ki$xCPEs8sqWtS9z(IuAEi*$#!#^n)2EkKcTqDmbNS5aI?dTRBn$pSop0V znc@57?=oE^Mbfjr>0m-RFR;!14*J8+W9I*folPYt;LsDPfkStej4KLJ%dCmPjY$`y zq_BtI77w@nb2Ng#@fwvCvSAc9ok$ZxS2O8Iiv`fuKq?0zPE(U((lJqdh%q$C(Ipfz zW?l`Eo}*zdRCYXNO@)Cw|Ks6m`$x#j!_erFGZDRGhm18>RX z@1NYKqBux1pA_UrCG|*FLlrz8`Q@YeXN*k=%B*MOK?NKlPoFr2>Q?0(LvhQ6duU;iU_Jm?3RiV zohOy=IkR?iUgq9|wcMCQ9nbYt*`Cjzz3zv3I{Mdp-s?Z9q$R*O_#b~^(_B>OO-E@& zPl1d6zllKX5exacrS$`^`$_N%n4g-Fn4=wz3a!Bd$Uq9`u(Q+Mg%3aY4=-@l5-bBO zE_3W3eu%S9fT+9}+#0wm&OZLuKG`Zp!X;r)L$&7(Cg!;iy)|;@>uzLOAF@$Q@A!`3 zi&3{kh}ia>u-={PVYZ8qGfP681_gXGBLqkFA!wg;Opx2vEM>=+GM6}>0AyoxaJ2O} zO&M(AGUtop!j3CK2zZDIA6T9xEl{AJcvu0`tB{SZ1JE^bBv6E-9>Li7na13ED!&ZN zSBO>1c4*$8T;GiQ%f}Igkg8^DT|P*c2hwGOoT$;KjydB+QrduDQj~?JJXGt4lxCan z%`MtS@15w*&VCx%)EOE^=g2opsU(Q3j~VUm)h z+CUNeR)}n&p~O7gBGr)Fb8t@EmbAM6u(pRq3-*~%W%>^4H4h78VhkcNmkYMv<)Zvx z$eRqr#R5cwGqN=fd4r7{7A7?Cjp#3sc*$ah0M6DA?2Z5M=%p9?;bWZkZ##c-LvG6N z^5I3EY1h`_()Jc;@7f35RYmg-*A9H=%!&-X=9={j57D84&|KAz9PE$6bjJfY(J$nk zpGspCjQHK|-m0V(S(^47^&u=4If`F2GgJ#sKC9)SB!burA&O$CBP;W27HHTtTGztw zcraM=C{A0uxcRt+hnAm4-=P?qwynFis=V}c&3So8XcluzrWg{-(pnK}smtwdDZq?o zU_`u}6m#rWfLIdGIu?K&6k}@G0TT?^APZAW$CN4BHg(`%rRyJgpLp0Md69PJb2Dn1 zZTLIu)F2yinUzo@L|!gHR5Fo$X4v~Cb{n7qWcGXXEqo$s&?qu9?_dp?{y}LbIDGpH zPMfCcIs^3A<&ZHCsO-<8STOg{EXwAkf>Y1Oi76Wqp)umiEWHS1a0$i=pk)d@#y?f(|X^db%&$9J8aL$X%cD)wpq9m>Di+#m8Rs`1 z(Nx>iV?@zP0brVY!S4dxgNx~M01n=Row7ER;i}5=FrTO(Ga9CqhRXa^FfFP(J77@M znFRJTzLVx~c(G75dC!Hl!nH!|I!$Um8Kk?jLH~EAE#5bfyY-pBREYGoUoL)4FMOvm zuO&>KCkAM5+*2nxs{3@qeA2)xY(S3u!3Z+uEn-=Z)HJg6r+(wgA8mdn#6D+ZUW!p~2gt=oQP;Vs zD=bW3n(_kJ@bS{Hu=6*{`N?e$urKi8@u|uaSM{EcqW)4 zZ(iD7vq>AmqH3eV4{IBg{LS$Vl3YPVP+URnx59K89#)o%GsA;qSo(+G2g* zOpP%9)@4K=fV$2{JpYF5Fu^vMdv063?)9;}HGbz+Hs`hwc}twoz^$I-qh_MwuV|}+ zN^QHCs+}$RzrMxVF4m;#Ib)o){r#GW^3bo*mscq*4-geUouqVxupq7~qTrnUO|)1< z`Z0?AzKb+;ui`usGh&gf_l00O7ngkj@qv6(XOqepHm6a z72&oqPFUc58as~)Cz^xy*F;WTYl%LtRC;aGjk`O>w7v@OO6pBETwp^?*bZai7HF6U zZ2RY8)J#FZvG@COPi|tzVIHy2w+qk}g~$v0kS~EwQ6=1Kr{1iU#e*CzL7x~QL1K6W6_<~P zG^t|_%42>~uugv*f84=5WuZ4|pzx0{>C>2Lq3PQIW5~CR--0V42d~sMR~6N^olQ)h zW@Fxp0efLGk)JHtt}fRIn$-nKJjuG!tv;fLrp}`qCX{PIteU8gPn6_i-iF@QU6Syz zfbzTU{*M4Rvj)Y&{bFKY@s6|>AnkHbov05N)P+w*B3DE1-4mmNe%zX(WUk5Bd|2~| zb~!ivO65LZNKtg?<>G8(Z|%8=yvYu3!S9}u#dZh`@5do)#Mc{m$nm=Bn+3@D>GG=u zMz~k^UxF@lIH8vS%snPb?sa6_N8mei#NqWdjexraDJRt|{7e|26DR7rz&J^!#P*$8 zJ{2cozz!4uCSu?-vv0}-Li18{+NIXS*2q*;0Sk7U?0?LaGJI2DyV&wLN&-{g#S06t zLVkUBW4-h#^dt}cLxNlKadN{r5@mAZuMkHPQh!pQ|7Z~1Re&IQwJ1PFe@YddvUolH zslYx=i{#hV2TwBg;SA*E-UpFC|miFqzY{INl= z#$qOE$yZJ$Z=Y@{9lxI~jB4V$T2`T`#)b2N|1XA!1X4hYOHrb8c)$ za{d#)9=KT@Y=e6Ir|H!l+i5Ds>H!vwF9?x-8hXK3{NyNo7D#;+Z6o$QR(@2T0=gTK zyf%uRDL4}$=>>_*b|zy3^RNp-3|tm7N5LX!|1GeGp7Ka~-KNtt)PJcHCOhgOJ5ZH7 zRJ$h%AL?ids_;V5;}^d(HhhrTFNHnsTEUO6=XEH(|?j(Fyt^c;M+TCKydi{{i6s%p)5pWjovAn=#6ek*9aA zAnKSJeSMKRS@PU`&l}9@PS6Xn1+#|s(r1*edBy2Fl(;0HwURg zd!M7cZjDn&6#Y@@~A6nLz-ppV>pV;x+E%KFc1!G#5;m%xai? z+u8hWC#1M=1MdY`#qLp+GYfEw^{G;H4@H`#@cQv|>_ zPo$o|b+pvzn&;{F6!g=oiI-K@wOpMMacnKU<9&xx%O@J@8Xo;0@0H~bg3%qMi+u;t!%So&6Lqm^u>y+uPxirkdj9o4GcO)a1Z0IMy40F`fc_rB9g#O_ zEhc{Ay%Qul)O!{mF*dC+Em|^I(qsb1#1Y_cyTXw z&jxb;l^(-ba0QT0v2MSDIn*dZ6kPrU)Gaii&G@sbB9IbwaySs=!%Eeggswf*G+`Z| zPI>un`NS{ErR$mR&6A}B$}0p<4$Y^1|0DgLx=?x`b( zSEmuzsVBY;Z|r}@!@lQUxR{C{pGSyjcJ~F!595$suhF*>J*RHHj;}yoVk}0w8Vo!} zH;NG+PdP^WQTKSeXJu6HIT=5rc8r0^)pw1Ld5z$X47VQuZMP_b=aop%n<`j`Mv~aNH{H^quPnkQJFLR}1DB^!IxnutRoVPG~w3nW;ARSuC?? zsBT=B^;oP4d!1-?#X0XIoh$Yo6I%G(c`5wwxsq(*inm2&dEZ;aV4MDUht!|&=1m1* zTc+6vuDPdeQ8KEt=pz2ucma;fHPTX*7BiO=0*!LTYYpN5=LUdA9+&PvPNckXYchIh zmy%xm=)2bt9vsEoJ5?b(V{MQwo^V1Q^0INdcrfS4KQPO32n_ zHAQ4ivaIJ{P3aZkQl#GIr!O*IhXvR9PdIaMG2?mciThBle5X~P!ooZ*-@?jpe2qv& z!Z%M+d1(KMyvKBwxVXm_j8b0TL~1qTni+soJm8GP|=ICE{tWHcq(ydc-T6!0T4O37SI5#1W zdq2b}d2ARb4d6Jx4Z3^UTjg7Lu-XhK|9py3jrq!M#+rT3VCu- z_+9n1vVqs;yePnQ*S_szL{LQxY+3VE@qnXnT$NVXt)|#Ng;Rtx&iSl~-)B^_wj@lz zySB=;%2jUs>Yw1#iL$bX;kA}jZ30zPc>#yJ0T4>X;JTofd75+J)qz!BtM6V9;CFJD<6&`+opWUdw7~hsMYuz zr3n>KlrOgYrIWhMSjS4<)M$n8>Qq*zi8-=tr9!LIlrvygtTGxXVX0r~Pd+2PeiLpn zdG^Osjjr&1#dlVo4^PHMH{1w4U}mo|m2^(iahh~aZ(G+fPA`q2u6`S0O#eDz`YO!O z$!$aIf7?#V-4JE6i|6&&l52kB{A7xO)l@{Qy1+Un7|MYq^6Qm* z?=6W`g_Sbu7X_5I=5qu)e_PNE9wUr%dwU*V<9RGM9TKJbB*H!1WVj1MXKu~e$o+3AX3O;^H9Sz?*% zu@I!{5;caTl{Q9Yj_g;|yBD1tb(qB{H@H^6-P*#oJs1ySDFg6oT(5uaTojn%%A5@X z`IjOf;?lv>CdHK8BUD70lrtD+8qdE}rYAj0(Ham}#oMenUhmCM>)S2lF71|R^5p@u zK(GX2=lytUKSd62>a3Wdz;aeMV;TTG&DorP$|0n^^eOAXoBu1O*(fE)Ugs2uN~`;H@q7gSD#>`QJ)&$#CJk0rkh!8@ zbz5;Y_nt&+!a9|P{BQZH3UVdaj|h$Ha2ai=0XBJGF^qC`>WlR|&enHYd8;#E(IYK_F4kcNmDmg!kr6b2l89HqX!p9X*Iq7lQ za0cz0aB>wF6i*MkOwa%Ucfb1|)41m|<d>no;|+W6+^UP86wJ{y!lW?g;nE}LzZ=hsz-w(u+<+Hs*U;P9rK_y>*#}wl-Ig{ zT?8sa#4PnrGX{Y?d(kllp1>mmdr7CTGTY7iyR^S_L}aBB4U47Ir>KZX;@STP1V^u% z;0@YR1@3^N7Wh8NJbDQCwUfwCb87rd6r<5s&U4@GHuUVdH0h)>)L#|av+A{=3j*(P z)kNuq&q!%{mEpLIrHqy1*gBriMwdKK)p+)L%JI#M`%o?fFgPk>kr&TjKCdggmG{v} z7s(Q@#Rrw+IA(IM(vn*vjVoLq0sAY)Uai>o=E$|3)ddzUezavwr z&PxvpP%KDX(hA=nNAv`CxYt&-jyIPHmKgIXZf+}$J=k#9_hto!)gem6$xDeg8V%`< zd_qVkS1UWy*r=6LdgH;dn}K!!Af4h3$c-}k@Y6{fnA=km58*?sw?OXi@k)`7{Uj_L z#MV3sk*%`W2ooA%J@JcI%xW#lsRFlJeDO`?su4LbCi4B+gTfKKQs5f$ufk4%s&lydy|9_DlzBNXN=^R}B~`tqz6cRkXM+mfe@#SYmq+jskU! z1%Nj=V>orNK!4ZdrRab2(wx5+Va^@PB@Lmqho~#FTA->+H9R*T8eT@E$^hgZP)03M zf^q1Ea6v!xxG7QGjGBN)Uq5FCm7nK&9G_sqed7d;;~j1u^V`Xrf7! z$%?bg0K1>idHyN>uAypb2epnynNpQlVcH-pD560GaM(nWG0p?67o5 zUH2h~A#({9X7M8R&rPu{M)l$vUpJ;;bbA8=WOjH}5Km z)s8b*?F|T4TX7~E;7V%f8x1;_jBfY$tzJ}&LL+TC?^AX^if;=(<$lOm(49!3SupFS zUO|GTfwH8KW#t=0KfY0qy$)Zhc+U;!a2B*Hi5MCrs!`c=b|_QYr*pp2&KVugNv7=D zh>yA`yB-X+Rq*^AW52H@j5Z(=JtoqP=eWRgbYC|-146w4KGE@B-h=QA-L@WGwv3ni zSyuq}2%-xMtI#hEYzL(eqD5o0h3TBY@x2oj!t<{;-JuK`Rz_OSi1P!~yNb;kaOBPX zqKi?T@QxvSGp4I$v1y9)`t;ojGEQ^mQ`nx$#|+(k3@)uhGKB9FZf4f~XHDhJFli+% zj(*=t>qyn$MS*~e4N-<87>V_AuHnL=TGf0I|`F+$)DT{Ke=C)b2kfKqkb7clK+B8!ZfKL zUv~*?95wpgXnr|5%@G7-yH;YcF*g{1`~du91VCIPJ`#YBWWeJx2xxvv&#fz1#&6hb zJL(%2<42#eEJBJ2OLBjWlD1-Vz4M7UMPWbxRMU-ds{}Ax6WCC3)|HWH&7|)YBW|-7 z2M?zA-vg^i6B7B-r%VVgWx4j75Dc+z6OK6rD2otYsjlt&Vm;9vmhv4He* z5&M*hYgP$&A2Hfp#0eO;c-h566DA!qhO|B`lhQMZ zG9mLGX#8qDbmtEk8JSc8zC&+xhc$oHuz&Q2J53pjQ8~{7t0KOwK$p#6jDv(9LV+%2 zL1@U@rG(Ajs%Z{ypahjMpF#9JX-eS)8@rOS`(xMPK(~bz| z7gEtmHz$j&yQet~PE2PdVi=$5yEO>sCO!twgMu4~B*@qw!WSv1AH_9ZYy5bCr_8rX%K|z8^ z`5xzlLU;$~o=l1L%g_Bf5#;zE4c0%Ir(sx%>*l9&UbHC5h?)d!^ashHw=BktEW@@g z`;DxtjaaeqFf=7-(!p4Y(zt-np^0+WfYO^Ue&+Yph&r6_8J4Mf&&uUKPss9ZW>w7f zZ|@O7{22kUn*`%F;#fP^{RS{>YiX8tknz|&QoW{TVS)ye0AH^Bm=(keWoM@}PX98ceo%}2NTUN2zLh?hNbBo6^RZRM00~gk=MjX@Az01 zXi#wC#FoJ$WX2T(C&!5*kfO{ht0rA?O4^Y+up62)BO>EX%u7+SU+nw{&;G>oQr&M= z-{y|NU&F34>oQ#OGaCvC28VK+F=Uy!#Q>#c0EqMhXc4v5&^Z0ObDG0$jS3b0v7P0k z6=h4)+WkQy{s&|DphP=umV-vt)B4*C)mOLQc$XGRYYwE;N#UW`e1hX5#B?LhBVx%Q z1MFA5?ym+hLDgIDfvvms{BY?e8J z_9U~_If#J65^w;bZFIFOR``V_m17XZ@dAvs%N>@M$UbegDVO;5EAx$gLt3V73Dw*I zL?`po?gr;(shEt%9??UC=wGkriN?QYiO(mym_>?iTgJeGR`1Xq!2m`Pd`HjDHw$>t z=Mela6B|(eT?@h%Iu&=>_=bZt4ITuBCjgB1-}Ihr-A|yPP>=WTZVX)H4KawXym$td z=j^KPbEh4msUL9TT^|TV5=d7Ny(Ne<2LXeHnq+_(OXK{;)(sZv{G!Pu@ktypPfa@g z#whVqg}A18df0%;)IPy!kT*G(5Rj%H`fEGHCwKQDWB8EA?=7gihO;cZ+dQFt%#~_^ zkBH58mNsdOeNDt_G>&CGU-oNdqcKadd65zKLWNi6C=TmASkpjGP);)oKqKFr5-Xgn z>649GE^3`O8g$+O9j_qsmscc!{7<7uX57w&)r1y4MXdl7s_|8K)~ z>2In76=R$f@k@-bEr5tkIM^T%hXsf+Gdr=`i2{f4;7qHqladVQ2G#9Ps&c*yz_Ksy zS%De^q6_q76lzU^rY|4vR!Hg{@0Ogq7>wDMvKmF$y`)lnqibeUkGpFSxb>UGMh*oi zY+f)i>Bs>(~kd8GMVR5&|2lG1pXtf4OJ z5Q_-HU8;T8^$)I@aaNOH<%)!{%C4W@^ky4N-ahHdN%g#=f@3}P4tpP`3vGjG8rWlm z+}v*Vg3(Ovmb-rhl(N5Dd=ZZqa>(;9Q_|`5-gQf+ivGM&8c_VhJG1L^CL1uDZL6YWx-QNk zKRm=hKCph({BjH*nh|Xd#Y)=7BNNvgQYn0>lE@#3UcMd+%Yj|hw@=G&S6_T7O{{y` ztHP+8;j##^(-<)zV{SLb`Rsgf*CV(oR{IN9@!*JFY4t2-1Wy?K=>1t60O9^P{k?~X z8PlNIPKn5EeFkoJOmJh=fWjaY8nAZ*YXH5z8n;D+#hoP-hDg~iLWX|}+lIn?74uy+ zuG)Y%pT6Ny*#9(XE|4W7l9hESk(KON5#91$g3>dh#S?L@$=+z+aF?!=-1v7`!V+TA z5wArz{raCfo5q{RuDIQrXwh_>4EAL2$(EJcm%}tbxOcQ<`U3}Ej|kMB_2Zh4F5|c; zF-N+4zeB$F$jmi7;_)aW*rSNH32_5sQtDnyBcpN5HB>iJ2Y5ees#XY|XK?>=p|8fH z%r3g5xPr#rPK`wm1$WNH?*|=6H25suhz*9CYxv)ceMoqXnx7=ZX8#y#L;R=(UnRjKa z^!ORuoi(|J_z>Z(FrGV+r83E%KsYv%O{4pc+t>rxL(9v+tS1}V}=KW(GP0L zG7>&P(%3dT4vLIv(~Q6N)O?1AHH(a&MU^VeF&+%@o>*cEfJklaY|B^sk+vghW4HOg z)vt26OwT*pm>4MOzw_hIBKQ6vBXFXWR3J~NiwtUP`GZHhO#JZA0y=G%Qiz%0`hS}I+7xDjS zJ|sVtaBJ({Y#U2vmv!4t&^+`=&fgpAVPI|;YY#M^9PMxg{hYCDyF0H=`|;Dm=9ZCO z^&w@EkFsvwtKOQ~!k;%}d>+?X2%5~UcQ~y0uYG8GTqwOWlv^%j?}wYs6*ue+Rch;z zb{{KN`q*gt`g&k;cr>&3S0&=BjJ1v(`@ZUL*ayKuzdNo_)r-%cJMUbz0IB{#HHu{u zW6YDw_}%+%$S+%EHj2&CuGyS(??R(4>u8w9eZmSKPJk8%Er=$qggk zKmtA$pJk~`5}zRJu%r7-V(na_eh72KM;#B-Dm*;VwKGls1>`i}Ry<6U8nlz26`cYc z&LXES#8OS0Aj~Pqhnh096`dN|G=A|t7;ee75)m5NUfu`Ah6Bf*%Ld$8Ion2Jb1c61 zC52busAl+Kiu^cSJK1QL+-@GRKZhDpW-5E`2mUZ5Gt_d{c}4jKep)wy2mjuu)B*i- zj$w#_P~#S3JV}~OcpB+*h$^R0S(+}x6G00-?viXk{7xiz?!NHDO4q>r7m8LPbDMn? zrnkFDD=B}WHZu}+2KW?9lV1o{kxZ2Pk@zf0pxWM!b;Kw;F!&oyo{h_ziKCOxH`wjV zEy(7ruBtk_TU{D5`I2HciEjhM?<1sBUo0M^cut|;ZHmqVMmWoF|2#-SW>S03-0GCY z7#EU)Ir0PWbyHu02FA|af+qNTJ4y3(h!vA1|4Jj&2rf2N{&hDnRbgk=!7t)Zv6suk z)8bd9J0rvH^a_vfk33g<{_oKk5$(19P20!(loZX27+C$C-MZ zxebh}I}9UqQldLY6~r-Gg#!cmza3VxI}rmd#?o7KUN}`TL1Sd5zh#h6Zn5;GaK1m2 zM{Z%GmXr)BvU+ORRC*=Sb_VB``hC7gt`(Vf9LT=18fR~O7nN+7KixGc&|VZaG?gl~ zYC$=Ty7N-nWK-wC-5IHN9_<+yv<$6%z9(v%;h99pne0RUdMTc*!Wz0TQiQOnqL|WB zA{NN|PG{u0s116Ja#Q>8B=LMAv8q^3riE6;@_ut&*sY2Ykv&W0{&oz~F29V#YeHEuCQ~dl?MdI~ z+Y(Lug)_&z$8)VUX$qsh-t03-ak=~^{ooWxVmYkVU8r;L*$7 zM^b70w1y=_uGoijQXJZKMr(LW!&t*0IuGgLszi=1oK-Ecy^g+wq$D4cXh#P@5i9v!Rn89Z{o&KUy?AfbZitpKTl=n)eJ?({2<5_{ zE8hCl?!RT8fF}t>R|b>{jvLSIx3sxFpM7*Wi8b>9r*X%P6+QA~h{4He0B1w+?W^bo zVew!GBkN%ekp{^qk?3a_@GD)#3Ek945I6P1L1ksx)IdIJ9a`ZuZRb!ixWKg1O2kL5 z*HnTW0XfFKjz{{))? zzUfKfngH*a5WJx;DT6vI%^1P3h`q88#~unWF(Q0E4rPG7*Q^>%a}2ME1hkY={-C{J za@u!2`Gcd>zr)Ti!&$aXRCUEOHHb3x+&jX-_zX#1aX6uQtCV`ER=wy{0cLY_-;pIm4UMD?=cx^F zTw#z|Kv+n1y7ryHzyuUe{DgyQLQ+X;A4KX!A$PIM*%ULJxar4PEK=<3MZAmfTJ$#m^sqI*E~j zlnRqqu3EpeM{XRIEr2t|Bt|rU-taY0>0HfbvR>CfS!f>TtCxe6OJa4wEE#LsYEGKF zO`rh2Y3+bHB6+QPHt$8%WPtOWYy`}koO$pAb8lx!T*F0#FXbrJ<-6U2gNeDg6U<)1 z*4FwJhGhiq3BfQdf5U=gI`9tyR-c+Aj?z)Did8e90#RGT{dIs;oZXoWegvvmMyP3rVL2iaJxmV52nTD9NAS>aC|2` zAj9^9TKVls{5)dK%6VKgXO6XyI1A9f&8YXOJU#z(xPR7o8E(_>P3@LIFJ}-dS?9VK zkQ!@|3JISk8fdFDY7}9pKLWZ_-*-pF)kG>vl%zG}*!Vgql`@!!s^JqoO^`Cef8*QE#m2sMh6%Z97qVU>Z4lAo(jgy+ z<7keFtM)atcR(>FyEy)P8;al8Rhs5G97vZT;TO=9DDd?olGb1Fh*Xe4G(T~f#|nE+ zxEGO_L@Jv91$_h=$HI>!au2&<&VFG@H90!+7C30sv-|$p3L7>qzidWEE{)6e15$F^Sf(OV}v^$*;zSiU8C{HPq33 zstDou9PpaP#M9_p-{#5S!OSo3jZ?g>v4N`?^<5DIywp|Tuy~^uQiFb|4k)i-DKm?e zT3s!MSlR-LZ43-^z3J^Pf#Z?G&Rn^!C3@3Tdb6W93WYL0n>smn1F6JvWw6&)?1*R( zu~MqW-6hHWiD98Cnj?!px6bk86SQJ-7WA3GIgMCb9L?gS{1{iJno_agpSU#CzQJcc7NYe?UiOn;8R1qQ#zOOf^XE)hZ zU7?2^0a=@cFGBZXl(wAgR4xuEjit}-D4?quc2rGy8?`ukC7XyuGv%3Tuc(rq)TLj@rq=dONpXN2 z#ur>gwxk%0P^#MQ(2~IS#d=%g_cB~-ZP4Et*UCAbO=I_-=C1{ZPHGo0ruQZo0pjm# zI4jr-(JWCW9GjAP)+6&dvYCwcz(vw9SF8SBr;|hab??(hiWO0_32O*}bbJBeI?6S&r67vn(haLL1 zx0*J!ACf4I*C!HbX_R2eyWR1xerHe{0Ng*nX)}ENS}ZPaJ)e^V>WK0=juumCj1}8* z7GKwXeqGFX918}lC#LC~AV$E!)CA$_z_Vh)8INq3;WH>iG)@aqg*D(Gdz{DVWSL^o zah%JLHG&YI&|1Jm?uu`}c3?`hA>$3heD66gpY1dJf}^GQO~1^(zJ(=ulHH~KL7MYS znx$*yr>|-_nej`$58YDl?G?|pCME|?KPdng7%iG>_H z-OQj*4uKLfCP02hOOY}yk?V$f&rkM2c%;9zGeZ0B=`fiMdd9!cqp3$J#)^WE$c&E1 zJ=tG;!exI9`H%K<`QXf*z`c8`Jg(lJ)r~eJ$hZT9c`qixx7RG?0!%P1xoBcoYsIxJ z(*6?2%bsri-K*b17NR*9X&;T&FqwJ1_BAg=4EVvSP<`;YV?=D1H_TFWPeenV6n%Gz zcpf&=hyHe}%AxN{169MYdjs?NQ2k4u^``mzQR8!CQSTr`kiBJS5cDu1i>!qt0VgC3 zL*-I1PP3A=TCiuQ_TIyAg(<@^GJbv5;urAOsor^R`RWFKnyye55Gy4S?9WnF4p;*> z+4!=2WTt6IcG#*_OP&9$_v1%Hh0qu2RIseX#A10IXCK}FF!_xaZ>cybUd{eoia*+{ljjoiTnfw%X;VJpKs<3o{60E17~Bbat#lCp*C^{_Lut}| z#^Uyr6;>o29L$13ZXJLT@gcbf4`VFAN@0oNWnLkzh9Ksq+E0zV?8IKl zJVId@#x#_=1GGdFG_hc{f|!4pdC*1G@wI1vc~954c3{g-4Hp}x4q(Wk+}BF=BeUgt zq)LkGCz9mFp2;3*1@;g8W5q* zC@&L}V1mUdtSp}o!3&l3wsc7_FJk##v^q@nYfbOz;pcUpq(IZKmfQ;=z1|2NEGaSh zN<`9Pzyuq~%4Yiv;*<39iNUH;w)xQmnl%S%55T{(AHR2lqxkY#0Lia@%iJ{>Fd#=o#x33`(;(%lh?;(BOtetP@{La{~ST&c=#G|IggHt&92WTAh9Fj)(6+y zFMj%^OAE&UGpqK*ADjyHYu%gBlIYh$=A4RO;%};%ATPC$ESWH>k@Z?I=7)R( z5F|s7Wv#>r<^lQEGb|e9-C=HSG7{eAqxmE|k22WrL@$iq=IM&}lHpyKNJGWSr<~!F zD?-z)Z+(q3UVD5&{BM}9u`{D7zz+IJd!w{T`J^E-C*YM_@14F@S8lqS^rKqb=dZ8W zM&0fS;O?^#??wPs0jgCaAh?I_f8AdH^)kHQ3g61`CD@+76%WY?HG990Sh+CllRsMS zp4_-N{$fCRWhN4#B@u~0jB1JY17RcIOdo4yWRuIgHd80aSwiL`Ra&$P^fD2{Lcy>v zIVqy4h5(NTa~qR-GmCJsa@!fW^si!vdsViXbhGgBLWyT=*@XcH4A3u6p911vrcLWk zv7+-6iY#}Ctla7kc;Ua$F^8#{)LnQ`DEQOO_9Kv|u)K(fj+Wnnh#un$Oqw|+O*`m< z&D87pucoPY&esI9&W#M;hs!vZ)+FViWT9OThy0I|-H4)dkGCh>sl$=Y_@Jx0FKOVu z${+HTXBSJcT1dn|dpmyl>N3*d1KbNj>oxq%WS07=e@Q`^w6^xG)hvmW<;l;(6tpca z(})6&stT&ys8|{MrXDGak^FYC!j0wCqjB5La$C)>zy%$SeQulbPip)H@G5aZM+{QKl3je3^2Le-~R-Qy3~adpEf_PO4EiXLoN^d*VXdOJl? zJFf;L_nmx_-hw^ua@XfdM;JT<#YuZypPzpZBV#o^mU60R_E6e7;haBp?b!K;N1}7!DWh2Ltf8ez&q0Tpl7Fxn!j!5y78$7K8b396fC$N;IQShxKYEZh_-KX?t|(T`Mqjx zaef55p+kE5b*Lxy-3PhuS7n-a%Q1w)4l%15!%R`r0~VV55*F<)b6jsvtdQtdmxsP< ziP<7%C72RSrx7a>Q*T|Zl`FpHxB2o(Cv@P|*E=sq9xw`e8ncC5*|*j3vNS*CkULrK zo~jT@cKms~(bFmn4RC1k8LypVy&A}qJoHR#6(#N{E1Y<=6m_n3Vg6nEd~LBox~O^| zSsIu1aX29O?=rcQ`0j~3LRCc2Wq_ABeD zKWaerF>uq7`>C|OTZX~kkvVAP0uyO7#nzN;8})+YIY%rEI)7JPEFjm`$WM39%)w_Y z+XfvY`P|0y@MvKZH1Jc`$5Hn(o8lw}xpKBuTYGo=X`Vf-m=oE8oy8Ps%D*LV~ z{~R;=AAA)pr{+q?ex+QH+GVX6Ow6?oN9yI;`ex=Bd!)1zyxXJyc(MBw9_6Tix@?+P z{PdzhPR;EJBnW%9u57mYb?dRY`X?vadoNG>Gp{W9VqsA9OVD8jjnzvghlId;d8sJg z1cAb#io86X6YU7)OM@-A&9b~;a(@6H1?!CKnP|zQis|i&q+v$G>WCBy-kUKU)I~RS z>D5A829q?N!K(b|v2ArGef`gmjb6Kchg!iEP5uB)$U{ULNKTT}d<3hRM)~oaec-Pn z<`ux-I9ar+)TS&3a6J0k2A-F{FOqG{?cVwFJy)>(|eCIghMLn7lT0yH@0=#nRFRH= zba}EJ&OwsDSl>(_H4AL!D4~@3{025Vk^P009IK8GQLGY&eBlu*E_8LJx`h@pFHMrBp}pVRp0I; z%C-P3@LbBSxs*HR>})4C$Aqwc*u6`s&~6p4IZ4 zlwvp;V$6gJmG{~BOxHg||9iLxwCypXUKYmRGtAe*8a4ts5nK~Vi#j~gnVcpXT#L)c z$`!+O;YR^CMOkVL;|wbTIlmJ;Nr|aBi`gFEjtb=5sIx+?*TJ&UyfPO{1Nf?3fiPi; za$`&5Jdxz`eerGNTYhkXsYIbLaboX1Op&L)E@<%b_NIhS%!^U^&RVFl2 z4u2YY7(T1lr5NXQ)EFM-t&{|{GMU*V8riro@B@1)+~{!C_-$Hy`nqaL+YtWbK@eB? zYkh}1ahX|m$qot0fF!d}x}bqYVqTvUdftKsL^{;NrN-DVOw&bluoi8rE@Q&u=z=_P zysrwl9A$qs?7Pjyv>!GwKSQwpU2VR;Uf2mrdb%KgV&z^Qy({77y2)gGyR9Y>qG`XM zq5)}Polh8hwmZqa9eR+iEMtu%QzYH($Fs#r9Nntnr)ledry{^wr`Ya3_`jorF6Pz3 z2$bPbZdOw6W8vnj<{BYgGx?{Q>vMG>e=3Aen2h;>u4rxF&9|KSlR6*KSy_9TbROhG z9wx+;Ok|=a`L>r0PF0W~G7pjm6Rg8oA z%>gCmIIQuez3cU zXz?KR>nr~3@gatS!-GV0eq9=y($VQxn$CQR?I+?5~681Ka8-ada+ z*c+Z5>(E-(=hvuvKiB&IE)P6B`3KC3rP8X0T2qWgioUAJ$`wXbR$jy*b}y%J{T2|^ z28pJ};BhAT2TQF+Z@|aM)S(>J`L!({8W)qr>ErRX&mSzS<03bEV~&M(1V~0DKmYD{ zm`%oP=TXqJ>{BJ)!P7^QLE@+HDKr2P%-{CGL62}ZdD8F12m^;>GQS#K z6Z#+Zn!KZ9#D40=w*I}Yr9M_A?ND(V+T-9yp^&saoPmlw zzSDdPJUe*1C$cLL)bq(S@2wtZzb4;?CWz@Ph`EKbbnxa4KCy_nZw9x3TNL{u(b{|b z``tqjFFxM>p+ITC0I-Qd+>G+8vF;H~qlmuf5l#FBl44yG7BgzlU-7>-P5m|s-kQ@v fMZAQsZZ|qO$;_}Pr{SxwK0K<{SV));08sfq&A=?9 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/left.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/left.gif new file mode 100644 index 0000000000000000000000000000000000000000..279e6710d4961d7644ea2e3e39e6afd300147aa8 GIT binary patch literal 172 zcmZ?wbhEHb6k!l!SjfQe|Ns9p|Nk?9f#N^Ekc`Y?g~Xx~1t67~r%;lSs!&jxl#`jP zkdmL9n3<=i;GJ3ql<+7`&qyuSQOE}IG8|GfOZ1ZSb9EGgQwvH`bCXhw6bvmbO&Jt_ zvM@3*Ff!-Xz@**Nzw-3iM{+%$5nXSNI_AHs_0#Z5ammWC>ec*qNb!1QNo>>3 NI{94w6cGjnYXFzvI#mDw literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/middle.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/middle.gif new file mode 100644 index 0000000000000000000000000000000000000000..fbdcf575f78a5ebbd3eeac5bbd9f963962ab664f GIT binary patch literal 235 zcmZ?wbhEHb6k!l!IK;s49|+DEpZWiPW*S3UTAH!3F#{MV{__jT$ShV!EGkg|Qki)Q zB^jv-1*J(jnaK(%`MHUid3p-osbxS3kJ9vv)M6clY!ENQAvLo^FF8L~MXn zDYZz!(9+VBLGdRGBLf2ygAT}iknIf2aT>es{4+SUl4tW3o}3LYCJ5%-`ZlvqY)y_i zON{zvlk8Qc_r#nUUz;+oS7*8wAfNp1ThKa>J&QI6cbF|deBP(?&CiC}j@vi=I#{!y ctx@66$5l65-@mTg36FLd3o%#&030@6>Hq)$ literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/pngIcon.png b/examples/src/main/resources/scala/swing/examples/tutorials/images/pngIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..bd2fd547833635ab465a796c9a936dcfdf4b3086 GIT binary patch literal 685 zcmV;e0#f~nP)L}=x{JFG>CwJ5D;t#m}DrRq)32-m{@Rt7*HUfm=IXNV4$eL@SH$^Fd$%z zXjoi`ptN`(B!GB`_=uRmD2yPGoKSFNfG~g{NN8A)6cAu&aBz5tz+h+?v>2eMc$h38 zh?J<9ps=W{IB0lqsBAEBj1W*HOPAS56LM;hJ$00DtXL_t(2&#jVOQxicDMK?xJC#$kXC61eE z6`~?!1rcMW6~E$=i|7CU9v?PBQe~Ad_RHLwI(2VV_bvFx6#oSfDDRv@7RX2~?N{N(R%R&zd#e0wv(eX6D$m5o=GAMo^6d3z%Q42eiWHL=s66(FHVl1vh@ zdrbP{5G*WCPwlS1d)wa8-m~yf*L6s!a$=Nc`=WEBx z8I|OWAmdKXc)1oaghWmtI0r$31bGE0NI~q2eOHhcQXqwmK5$jDb*=T%ioeZobIrF8 T1OmU^00000NkvXXu0mjf_nMS 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�nPyR>u1>t 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/right.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/right.gif new file mode 100644 index 0000000000000000000000000000000000000000..b256e5f75fb1f5467251abbf9442f338892e6ab5 GIT binary patch literal 172 zcmZ?wbhEHb6k!l!SjfQe|Ns9p|Nk?9f#N^Ekc`Y?g~Xx~1t67~r%;lSs!&jxl#`jP zkdmL9n3<=i;GJ3ql<+7`&qyuSQOE}IG8|GfOZ1ZSb9EGgQwvH`bCXhw6bvmbO&Jt_ zvM@3*Ff!-Xz@**Nzw)%~qgf4szES6oR(^g_8+4;}QR+O8Rat3Y55;}UDY3n~ OBkprQ{}oXN25SJXnDYZz!(9+VBLGdRGBLf2ygAUMi29WIx%-I^d?))<_JM1*!l}uu2Kl{c)an9BQ z8Fjp~isqGPnlRppzAozM@n_rZ?DB^@TMqI1Z!lq-XpvS})uOfhlGZ1!vqC)g^DkYQ rbCHkPIiy`w;vU-;D{*7rCt7AIb`rH-)ly|T)gs(25}jS#oD9|g^MhHm literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/stickerface.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/stickerface.gif new file mode 100644 index 0000000000000000000000000000000000000000..b3d29955bf80b7dd76996e6294d06713d615f489 GIT binary patch literal 26850 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/sunw02.jpg b/examples/src/main/resources/scala/swing/examples/tutorials/images/sunw02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2addc1adf82de943c967c71ea93f9c9e350f6365 GIT binary patch literal 57300 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%0D1!>XAc^<@Di7lp0uhM!_^~(u@gW0trSq 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

-7Vac+Q5RUle5(9mliEz-ZG1b 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/sunw04.jpg b/examples/src/main/resources/scala/swing/examples/tutorials/images/sunw04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a7b4797f15053c29b528510c13bd156598817b7 GIT binary patch literal 54051 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tiffIcon.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tiffIcon.gif new file mode 100644 index 0000000000000000000000000000000000000000..84b41328edd8cb7bf351e951483c2e13c436edcc GIT binary patch literal 565 zcmZ?wbhEHbRA5kG_{zZW|Nnmm28Jn9rtICjH+<36Emz;_1myySwp@Lq6Oix)4JmXpN}Qw9A(-A2@J;p`k%ivS9tYcMS{;3?Dx1-@m`UzP_teU;y{zk)QOPPxO z_c|*+E%jp;dHap?pWD6sjo}yk*57=~Sz|PH``)bR*tp;VCJ`rQ!ID&ArbfT!+O|07 zx|%-W2{FYp3q)!}3YlgunN=RJAbCngmtbK%fM3I+EF z2ng=mdZ4Oc{jS}@C-YCAJaE41T;b)*S6AG9&p~dL*ReLpCSR}LyS^NEi#&$ zQcf_)+S&!PEJ!`g!H}@)N<+|7>j_GXJy%w4P6_s%T_DohV=1!iFc@|%J(sRkoBqfFjs-W8UPtv_yqs} literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T1.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T1.gif new file mode 100644 index 0000000000000000000000000000000000000000..efa6741f4f799d1773685890aaa0e8432525c4ec GIT binary patch literal 1934 zcmWlYe^AtB9>!N#a0P{^EnQ`$u@oEZo=ru$plHJnHR6v;1#PC_+$!4UEa)POZVTf@ z7VQcP?woM!am;lqSholm1#J-RMF~f!h*4pDN4Z{F(a9mhrBiy1-a32n`Q!cLo%ue` z^ZmT@ZrHdUOWRdxAPv773?xD7l7U#TnZj3~1ctdijEInuI3&v>08Zxv0YwI0k6TgX zfWSJPG(af@vw6K60?A7145`)GJY6;hz#c9I|@k>`2cj-_du<2l$2>%t+6x88?Y5ytN1 zbX$3Zw%Ig{CUG2rESx_eNs`mS&~!n->vh6;{y>1^c^M)2A<0hDHi`m3^i+9yQ4F-R zyaXT?LIPlqjRG+0v^y~b_0@X;kZ6iRU_`^6cG{tb$(UVL#(}H= zMG=Q28Objk2r}_3i&{}2 z0am!GsADLC*o$m#2ZO?h$zb$(+Y?NI`BI}c= z{xqr%h{RBeERw(^Y4X`P%5BmzYgO;a_s-ZvzxiW!0wRm(QR zBA7IrA$x@bf*@JdbjoAxV`h^{Qx%e=!T7YMDX@jqq)Cl*>ISOz(j^oMSq-{g{sn_6 zWC+c&5Ul^Y%QSy!fyjQ@_c@f9(@b1A-Ctu)**7L$Xc;&OXH{D^UThsah2*vs3|>5Q zvk@))u6bkESGWF(l}?NecAdTb1@4Mkl+zu!(?XnDy7Rm4ukW2DTXJ?j&m0(O@a_1z z_u$GTqy6DXhw|A)h&o*E_x>g=>z}EIA71WA>Jd89*-KBVo5@YzCvYXVm58)u*58(0 z;YR1BbA`u0EFbTwJvT)Z)~(4|_cu#iLfy@U9sId6XDr6&XM9{xM(rFgF2C`oRjto= z=Zi=B{?QR};Qiv7iIL>G-j2AvW$zrx9fB;Euk?`(fk-|ybNIZ2?K!_8 zH2zBO@nwgeoEdoW_PSu-to`2z4~)k*SH;CK6>mNMesO7bAUOX-bSWoS8dr*03zK(D ze*-OPEo!M;8*S2&bQAe-&L6x9_kGK^t}GRPc-&aR z@nLg=E5590Fy2!8-iv{6WUlOG7HnAA=P8U@8>}ykY6{_M_1+*i!x%j`uaG|8$L5;C zgX+&&F1oF&I=nXWZcfZ4w$K=DWmAUDsGR6cO7ZtpuG*>o{JWOfllwY+Il z+8tkG#Z7ExTIN`)Aji}pTOMz37+rx~H3qOfb!+~)8wbG?*^>*B!5c&RS{2o(NHhKfT zh7JhxSa)%d`5^2s{L<%ARb?P5ew`h9_w-z=b!6A8r&0*Rj-&nC=fZ#dF(VsmA}dSw zY+0NLugCVqxzt|E!La)OC>q6~ literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T10.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T10.gif new file mode 100644 index 0000000000000000000000000000000000000000..ce92fe759fea7e4668e03acce848d800dbb356f7 GIT binary patch literal 2083 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T14.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T14.gif new file mode 100644 index 0000000000000000000000000000000000000000..6b0e4c7b1cb030abed5f44c43c9f6dd527283b2f GIT binary patch literal 2090 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T16.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T16.gif new file mode 100644 index 0000000000000000000000000000000000000000..d7ea7ecc02a3d1379553ea4155df141b1020e3dd GIT binary patch literal 2015 zcmchW{ZkWn9>+I?hlE7f0_uXOYlwD1#8tq{QLeK*FHbhDc%~lLMjLEYO4oyOIrZ%F zq(QJyz>1cR5u%L_)&;S*WoTVs6P71gL~-lT&T3KP!*oJr+KhKSZt;(}*SzQbeSaRl z^Zn_Ym7S^k!>&p|5BvrI3kwV0MLb@w+v^p*9=F#cddW^NYV@K8FCs}V%{(5r$0K?? zg2z4Yaf=?e;9+NG5!{Q2ZnqS8wVNKV`xr`yPQs!lXbB! z7t1a^tLywNqLqjyf(F`j!Xj&3YQx4kUpg4}=Sc+w- z0fwSlsZN^ebWnC1)oODvw1e(*P|}t}i^JAxqbXZYpN*nyHhY`BwXLnbRifV7*xJ}A zxrLPKdMjCfxXfxXTaonYYAb2AkQPbBBvD2}$(F-q7J{@877IaG2(!glNDyTNVI~M8 zVKx(HBVjZa7aF8wHkr*vqp47D((8>zDH@D=gP}lg(BlRWDkw1MC2(AiV|onNW0)R- z^1VvyJhEWh& zjEEM25d?-22!dfPEI9ykX!-$KZ#v@Z1FDuiUmNXh{P#d zf0ZIMrjVn~4ITrda@z2&c4r+Fzi)=?>KJN((~d`GciV@Xk!_a>hr7>@o64k^t6xr>#i{~V=JYrwJ8;#yZ<^*Gw!fSI!Lrc{$dj?~yS9`=yAv-&?Vq%r zcoMknPQu<>XEv=J{aaSNdD`*zQ}(m-@P708{+hRTJV5pn*LH^9UjE?ZJEZJsO?d}3 z9Q}P*TC*y@`KP9up0{&5w?}OJ?o`I5n|Vv(jC4h6T}$2HpYNfs6jY5hC6?Tunw}nc z=v_`+V{R5s-Tk3UFqsd&@n}51u%qEdbJhMO>J!_a*H`2myS;uq{FleB!-Wgip};HR z_)S{%dcu#pV`p|24NsihfL{4EtO5=#?hH{aQ^F(`#pcO(tn_BjX8d^yeVze?0x8uQqrpW@+c(EzK))`-9CM0R$s*}ZEU#yBR2f==*%f08-ltH_Zl%MUq-+#7v z=SBIZugXwT9zpM}Z?C&Qsgn8Q`YN>BjXn6dIlVMDJUDqF2h;NWH3z0wKOX@aa>Sz> z_*qSE+>P0g+Lc<6XF3jHrRvIm#dM#D@&!fGH>%|TzRqs?1z%m%$yCUulWdjo*XdNQ z{SaK5zoM@sCMDp_nR}VxMd@#*2KcLa?3+Qs2Z(*T<*`-c(p9Biw?}w@0BsAEstjS1 z0GXdo1Y~xDM!%8Y11UAYe>8akzG~vY^`Kn+oZPRlugevbym=XL5SB+AX{0rc+Flbe z2l&~GF?=raRc_ zf`2Dofew9papd;CwhDh*!Pahhc5flTFP;+sCaR(D^0j-%CRX;#L%eD-{yWMVm{|SK zx2z*R<}bRZYo9+MWy^}0kyYmnr2%zWaF#r-g!uWz)98FP%(?QY-r93kM%Y4{Zhf z?tHRKozP3({V{ARJyi8*Aoz{GxrTjU8afVN)zq!1^hbQ*Z(rR0&}=_*+Lel_%(^I5 zcyDD)*}0P$c@rN!_)ECoNJjjUwt?3^$^pY#=G5;SqQHP#h1X2Z0n6lAXi# zYaD1lVpQj~wJ*1t6l=@7d{nqC*g-D^n8xEd^MIxUbgg*-s!?~h<`Xb;1N@J%JxNm< InGAUCfA#c$rvLx| literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T17.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T17.gif new file mode 100644 index 0000000000000000000000000000000000000000..926668e76282ca6113fd40f5dbef82e5d5ab3672 GIT binary patch literal 2115 zcmcgr{Z|ub7M=kD0b+@Q5;4+2QV4=F@|i02gn&9obOWWwXc2?58U=U5N^R7*1>uyB z1O>z+U9*}BXj<(W0cEzvbB25|XsAJRFh^OOs`ZQ>v;(pj zewqyh>qXh+#~>N>8wB}$KCd5)*Gqf7l$V+HGPIYWy!eE-%Ip=&y+WB60m8rpwUOLn~TJq9?B_i zbMk~F=_dWaNzz0T1Zl>H?Y3c?eb{Cjwm60@7Q5XBXt&wymLWS~wG)KR?Y5D_wqYQ< z&Ec>)z&+S-_@}_!`>;AltJPw);(j9tU>2*zVsTjBry+-fu#)c|1D6DWo6I)CZ0f{lDaNGn)m_P=F$p~mN_FUE*j5uM$aia;yWCU$LIt?b1!3bnD81)82k3rvM z=+xf|D3Pgo#DK0Z>2@ii%Q%A|Z-qfKrGGg(xBr0w6$qArC>%Dy%-E~V}(0^g{jOf6NiIM(`cg~6H z!{0|fA=kaT{2kl@RjQ5V%D~6d+r;K?>{uM zWI#D~p?T|#wAL$?s&5Xx&fn5|cHfwx=t$wq!X2IGejI9@lV0huCfwuQn9EWP>^38( zr|MVyEgg4t-8|ZTsABn`>buOh6Dvxdx9w=!x@-N4n9SXmuEZUfc@rOJHvGK0GI;dN z`N`OIUmUsq;9$n?JA-4ApQdkLtvuJ9`d{Z%O!SKwR<-ZQtF1NrfA*x*-BG`YshMyZ zLKgi#b^ndFRJTd{i1R9a-<^gFwRR zq!Y3kEa{r^9xu~TA}U(>YI~k;*$0S;2ncgix6;S3C#~fPYiC(Ccck|UU>I=`+SKtG z&Z@tEHnjus_l%5CliNKp1byri0)zYayt*f?W@xIb0LzVdnGno zAGsn6HPv#XOA*_tEHp9?GE~f5kQ{t>HxDw3i>-f`WIQ+)9-dJg9s;|@elf7imu-aL zhMn2~UDg9(VDIHL0*XO*gl=wSQq81PAibIylK()b!yI zq+P-a;;D$hvEz4J!@eYoKRdqHU};GlpXjha!TQ4l99+^C5T4v1hDYNHRRq+59(b90 zxQlK`xd9mhGx|JlYe%ylZo*?;0FHBvXo&4ajiU4wrSP)#q0l?BNzSZ z;^cm3ymmHzl9T3It_$)}bB{8YaQ{LIqMdO17o47!%;2()(eL-Xl}$k>eV@!eh|5Fk zSOEj)o5juQ?#ZKjE4puqE!?-iJw3f;YV`msf?y{@+_6oolqJTNYAC<&mitdzVrQVr z!Pb?mNM5ck!hxN967A-62PU5O9)0ojRHSe9^yhz|azowk?vBz4+ay1vYASq#53P-* zCRQvamS#H#t_mWZuGHx_Qt(#Y-C(5`v3t>Uqwf6bCfF(?A{6wIZU;XVTZZ(UQkRV}OUcyjL?K2_w zSpI|~`s2gvGJQYxw}cvh{c{9=@u=&Un>iWJcv>Sj3bN|}93y&eiT99xvb{lSJ4Yyur3? z-p=%*CAwAh5VyAd2*pY(o8P>qZ76)dt3IKrS{o~s228#tK3Z9qwDR5KdHNYhc)o6J zgC35ydh7m?zztwC$09Dj$xlvDG=7d)7hFxjVx-mK&A(5DII%s)-3pEZiC@Io#ZFR} v3xi-4wMYYxFO|#>EnI7hw0eS4YTDOS7WFK+WDNS0zis}Z;u;wYLu>vA_7Ti} literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T2.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T2.gif new file mode 100644 index 0000000000000000000000000000000000000000..0e2a5ed73c773c40ec837f375aa2bb4640b68973 GIT binary patch literal 1898 zcmWlYe^}E78pp#AwRi=}Kn)l$0%`>GiBi3sGE4gFfMhyEv;CMunh7gI38DH7KW1zNNe~R2@AbGWCM(0z2nZWU5`|%gqHvrbaMD@rs)R5CCn%~#!7JTf z?+8MgEmoFgIF5GOY?34!3tGolk&kmc?{>QsNp{+t0w3ggLEv~v2-;jO z3y6kVT{efGCIc7nVQ@Onac-xRZD~&1N|Gc90*Pn^PB7anqA2DR5e!XnywK=z55l;~V2}k7 zfngLz3f^3JF3q2?{0HY!y7u6=}7!&nHSjS(ZVK z2GoE>Q2L10$O|K~tbiaWDGI1ckQGUzNeJ?+ER7nBEs7!`5GW3hG9F%0LW4u4jE#+D zg}euT{RKcZ28=~P1nup#tKu_^9DSl|uO_X~L$uak+6QKD9pqXYdcK15zJv zm~ARO)ifGbd^G;_%xL5Jy{^MAaiNg!9Z^Kbh>BnZb)~{59aE2l4hOd+E@Rll|NJ-=AMn+t1dOUP`>2HsCtp znmQ_ty}Wh|-&RwUbo|e^-=FnSLYey1=C$~~#3?N|{<8GAzy1q+_lxZO++OhZfoV_E znf=IXYebCaU)o(+ZJA8l?owy>(rLX@^w{}1>o!r@`FY1H=gnO*{Ck~$ z$|G)O6hN5mu}gXqSRpm$B@n55{jA^;d>gg_N%`jZtH*kbWkuErr`eH~;Z2t#GjFR? zm&e7WX@0X0j!zGJYuxj9cQh^2XFqGHXUq1-!Tv0MqJA)kY@d;K;c;XunG`X(} z{Mg!W`&Lhj?!KGwC}Jvb6Ds-X;`rzG;)COd=)SgU9jO*KXWmtg<)-Sto>1L?Lbvqu zS;JMpv5)eYHS5)F=lc5&zt=W*UgO+G(@t#_e}CUsZ(_A)QmoOgalvP|7Pwz+U-*#7 zZtc?@VQc>S+g$PHw+~kRQkp$!02=*b(LL{uzOahK73J4k?`JK}rJ#hq1<}I1!)sEE zmW8(tY|c2ZyEZld&Xhy$`yUjV{?YJsHl%TO&QQydVcV)pBM&;{RbgTGJN})OqDna@ zPY0$AcTEuCp4bsFA{rWj-(;#H|F=F8{-JZu5i>sWBn;5kI^khHGP&NOd666${)8!B zRXq4s)X_j^!4}>L;p2wb$czfs1qxwFifQufz+R2%+&`l@ hLud5V`aIb2Fm@n5X<5JW)Sms&}`QaLs9T(z{$Q z3L=A{hC{fF#xp7^W3jFfb+4s&D~WcoLAF!$)*5@OSlwEfE{M7^)ZF&Hf8NK;d++yq z@2x3YjlNm6Uxlk)s#HAB`g{!xLtz+#VP-RC7C-|GfC6M-8CsG=6ft<*ZkcEx2!eDt zI2bR*EFB$woUmb-p(7A*kWP+eI6-6>8i62&q9joeK!ob-@cFzv&yhA8ZniKK?S>2- z$5;V`=6D1~P#AGLoeUjB&A7MDL)u81X54NUhN5N+bC9Hsus9uVUXoZY>U6mgy@6p^ zmSJr+LauN*9At;z*WmWl*&Q_9X(t`BBrtRbf*>MHU??JviwYi&kJt$tngua5vV7 zJF`%R2cfwK@i6)4XoLp=(9yuivIv5pB#r|B$nsGIwg_Rc5|M;}pOY05eo;9Vi|JH~{PGJb zbxajY&N5ShYqjc(C03R?89E5$l>5z>PF+6)7VM0&mrj3q7&0|xm36iEwZOkUZ|&orb4r+=lh}0mL0m^Hp2cnr>I)` zU+dnp`9I$5lmek8xqZj=;*>{icQxo2(OpS~Tg#u+B=wKwz1P;`HtWyUaX%b7JMWgc z;C)RGc5!LflzT{{<^6l?<4?^et7bd5OdY5`_%6C?ddlL26Q4Cr^c3D&wAu_N0(ZZ! zZM_=%q-Ev1$2C){;Fotky?>>v_F3y;_OUIs>n{IJc4Yo{tq-5A9A8y3sJnC9CiP5B z+x1m{-ez~|s} zC&jqG8yBr_*xop+d2;kiq!qr}-|3a>jjsaBOVb+*zwKMlR0!l|ZHhdrJfj{pdQR4_f0&ri zEW~P6aq}RX3Z(SS>x$L|cH*h?r5s&x{e-PIy?dK+Y1{?I826X7iSzZjlYnL9H+Q|N zr0xsBQ#$Zffcv;K%{t{_^(-rbUyiBQR=%Yr_t}@Ky(MwknURdI^S358AJYwQp8JM& zu|6-7z6O)*DP^js-kDo7+m0>RsSOV#W^&%un_Aifak(nzpS;uRD)Lhb$}AGoo%6RC6Ul$t>Tjp&3 zaI%WKQ^_Roi^V`+;YoW5x=j1f)j68#rfu4krvm;g=J zS{jmWJitaS2uuE*AD4Ecx#{AHglV&ggD1(+>7eVU1s&8wlU|cJzuh+bouGP=uI0wj JgalR5{{f1QsmK5T literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T4.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T4.gif new file mode 100644 index 0000000000000000000000000000000000000000..f7ebea23e886dd9dede9be2e7b49b764f5b213e8 GIT binary patch literal 1989 zcmWlYeN+=?7RCbx2#93(P)CGy1nfo+=qQS#LK#3LD(+^Lvrd&t5IjvQg}7!lc&Lpe z$beYWiW)W5QK&{Yt0QFBX$|fGQHFv#tfq>I8W7OhrmF`F6MYcv`S1_RHt zF2bSFXef#%85YOQLXiam0E*=(j?-o$94i-beKAI|Y+*5`*Xu!rlAvgsq8Y|(v6+7Z z(ZDRjkZw|^)8Q7Aiy-Vc4uOyyJkJ^QdeZH(+np|&L12WY85EG^D5-hSuo9C82?8e} zW~>MkG&(`x?aella2df&N3%nM4Jd-Z8jTj!(lqIEIXQtJVtrZ^H5d&n%i8P?nT4R4 z8lw@05hN}}#zJ9)mxuDK!1EZ4QnW{cF~Z`YX}U2zfYEGm(ViyUq19<|3r>0{1cv?4N@uH6Zzy*WE(Fzb5G*?ZYhY%O z#Z5J>lx!Q1qKKgwLo-p1ll|jNW+TUmG|RvVDH2>Gh$7GMq)&b!4g^5P$7&!5E7B1% zA4LHQCEZVRJTG?%ydWoCLTYQXQ(sib$Oa;a21>;pxF|f9%yusaS3ce{YDn($aGX%4dV-`$=n3dpVFsx5af z%sHGNH#Yx7L)viHiI{!&lABb~9ot%_XKc=>%HxmE>l=GJ3&$S)-8l2dPd8QNdY81E zTsY8pP5qA7I{ntn%=N=(2WHkbz^lN~w%NO+XNebj-b;Vb<`lmI>aQ;!-NW2FS@N%a z9Ro=p0QRf*BA4DP^B!o*OS^Ox2N&B{&Hhiw_6z@Gf$yL0NskY$E;yg~yzc0)N!t*j zef#?B@h1Y<&QE7Q-rYZAQ|*IgFP_*=4j(DecK_8orQh&&zTwN67y9d`oMTt)?my2? z+naCcoH6Qn^mR_K_x@WMt;J`7;LV`R{^7W4Q7KzR6iNICAj!^Gv#fv-Y|p3gdz>Q5_k0zwiAV17a`B8g;jHUH|TN ze11ZZO;l%pb!Oq^93SKf|E$VCsbW6xAi7@J;7o_rmlBHsh>TxsU7GI>>QDZBu(Zub zItL=MQ=dYoZz?;AbzoNJ6<=KRAOBQ8>j(GYh`vczKf%LbwW;16(i;;QeO(Lm#BC@X zY7glX)8W3G<(LNzajw@zUln6*OGzc^TRvR8C@Pe~e$04t1pQ({Rle(@qED~f(HnED zFc33&K_cJ%oVO+e-S>kN&(xt42?q{Efnrx5@<|zlJgj`t(jEUSsWKI6g`XedCFR`^ zuroDp`4ekkBq64D_?}Ik zg2wLs>D!HyZNFw?%9vl0-XuTz(T;!>e|c(mNyqre=P}*Z+s=xh2$R=vZ4$S?5rZoq; zcoDKErF12RKkiYG`zRPpZg5z;=1waBAO{*R{lMLi{J2|q*fMn?u{9?{-?-M)32s#k z-#0)+ctn&^%)`}%rHv`RN(E#|>RUscxA`=?wzy7?i31@e`q{gHhLunLQV={HkNQ}> z+6P|Rf2b@0ZL(J|L2r~^Gez=?kJm7v9=378);#!(4WFw-YuB+Y=!F_w;k{CqMlU+5 P-q$(9xa^2Up;+;MX}{l3 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T5.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T5.gif new file mode 100644 index 0000000000000000000000000000000000000000..eb50274c304049c1f109870884f3a0fbf171edb1 GIT binary patch literal 1971 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 Hz#IPokDXuD literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T7.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T7.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef7b9552586347fc4c3bed9f6c233bc0dbef7ab8 GIT binary patch literal 2076 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T9.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/tumble/T9.gif new file mode 100644 index 0000000000000000000000000000000000000000..7a104bfd841cdcf280deabe5e5f58236ad2e03a6 GIT binary patch literal 2053 zcmd6m|5sD@8OLuRkc5O9Qq(|^bHOWIA;4{*$E>BC5FiGOYlLFsfze9@jKFbGaf>ak zmk=;QY9m6H+9;ty8z{#{z;oi}mk@3sNLs_xnYC+sv24w8Y`rqt#hq^KL$^O-ujl=F zKVN^izuevBa>=fG1Ehlf0YU5Q>yZuUNF*GIP!T#Dp{a;M7m?r*3`iY8aXJ#FBNR=C zX&QKl4pVeEv=X|%f~vwa6%GT1!f0z4E?tHt6cwVV;D&{Q6sn@&QVPaGR47CR!3%|e z`$Iv0$nFZk7-)i_U@+(p20cL`7VvxKeWc&xpPM6RXUSO~32c@meLfO|&kJ^b(mzLn z^&Hsz_vn9XlAI&KIXK+FP0n~oR5df>1u^59@y_`{_JVE$_q31n%*=Yg#slPW1G$0R z?x}IN%k6eKTsPb<7m&*}?i?R?j1Sw!VX4#Qb~;^7fCI?kwAmcP4u`|$u$Ubtv)yj7 zIh{6#4UBCTo6TaenamcK%d&w9gvDgC5N5N*W+vK94#$rJv&lr52*RY(8woQ(v=jPv zLZ>GrwS*AU6NFw51kmYqI=xn_$8o(-)Yhie0km437S{rBT#KuifQ4VSe);{Z}u~y#tr@q?At# z&!0!D#%kv$MizdJ9gI>v`am!w5+AQ)PVwHo+ceM?_qLy%Jkb=uX=+ z+j>AeSXKS<7ZtSpBaOc=y{h}f%H}II-xAw;PaOET{N~x0Cp&+E_P=r)sXsHhTmAXo zto<*vRKNDkrkaT{eu3tYC2O$S%=>M%Izv!rwIk!-nR$>%l6{+btR*N*H(oMXIe)p^ zyf~D2^NO8yf5j`8eUV$MT{tpTDf*X{gTz@;$P6XgFSH&M`=*;O;!vw_S!4QGnGNmzM>S!W$ z0sa$LxTDF~DLU>JUbd8a)t+cUD{jcRQ*iu2-Y?hm=a8-&?)Q7e8uoS~M#*NdF0HI8 zM0eJVfy~NEq%`|E{7j>@Ci$t9(RD)>6~{_>#H;k%Wtt0{MvtBufCOVp);s|{$hqlH zkg`|^e^34=%YLqaC_>oJ>AXpY?5!SyjD?CU9^qn2_2K6Wo9ljwL(W&igDCEl1*M|*M!ovwAL>;cxuqzDCpJ*YH^k<;rNy~-RS%Z;{jGWYy-#DV@8iWyKI)w~ZN+89ad;;t zzZXEhK2lwO@nX&c<}^bIWiDvzll{n(6R~mRqbrp^v96!wDRWl0vfkJ%*Duv9MSXXS9O#V>OPRQRb&qHsz0CV;jC_(3=FA5d znAa}-;9+XmeHHmd+oJD$GnKv8l~?@Mi%T(?4xCHB9jN=k)d#;M?S;ey!ZIfQeV%`B z7sAZTAjOJVwx&cT3@un-}4u!r07+j>eOjndGQ)nqveorMwn6jd&kB4 vwxumTtW(UuV@KhGMMIKqxc`8BaD~nv!42Yv1TUbRgykXT7U@<#^wNI-=A2== literal 0 HcmV?d00001 diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/wavy.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/wavy.gif new file mode 100644 index 0000000000000000000000000000000000000000..c9be4659de0383a66116ac4646d0a78cca2bdbf3 GIT binary patch literal 194 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 Q4-+tvdOqY|0ce`deQI5MZT6 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 literal 0 HcmV?d00001 diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala new file mode 100644 index 00000000..fd2ad3d3 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -0,0 +1,324 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import javax.swing.border.TitledBorder +import javax.swing.ImageIcon +import java.awt.{ Color, Dimension } +import java.net.URL + +/* + * Tutorial: How to Use Borders + * http://docs.oracle.com/javase/tutorial/uiswing/components/border.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/BorderDemoProject/src/components/BorderDemo.java + * + * BorderDemo.scala requires the following file: + * scala/swing/examples/tutorials/images/wavy.gif + */ +class BorderDemo extends GridPanel(1, 0) { + + //A border that puts 10 extra pixels at the sides and + //bottom of each pane. + val paneEdge = Swing.EmptyBorder(0, 10, 10, 10) + val blackline = Swing.LineBorder(Color.black); + val raisedetched = Swing.EtchedBorder(Swing.Raised) + val loweredetched = Swing.EtchedBorder(Swing.Lowered) + val raisedbevel = Swing.BeveledBorder(Swing.Raised) + val loweredbevel = Swing.BeveledBorder(Swing.Lowered) + val empty = Swing.EmptyBorder + + //First pane: simple borders + val simpleBorders = new BoxPanel(Orientation.Vertical) + //The method addCompForBorder in the original Java did not have a useful Scala translation + //because adding to Panel contents is not the same as adding to the contents of, say, + //a BoxPanel. + //AddCompForBorder can't take a third argument that is a Panel because Panel.contents + //cannot be appended to. + var label: Label = new Label("line border", Swing.EmptyIcon, Alignment.Center) + var comp: GridPanel = new GridPanel(1, 1) { + contents += label + border = blackline + } + simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + simpleBorders.contents += comp + // addCompForBorder(raisedetched, "raised etched border", simpleBorders) + label = new Label("raised etched border", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = raisedetched + } + simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + simpleBorders.contents += comp + // addCompForBorder(loweredetched, "lowered etched border", simpleBorders) + label = new Label("lowered etched border", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = loweredetched + } + simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + simpleBorders.contents += comp + // addCompForBorder(raisedbevel, "raised bevel border", simpleBorders) + label = new Label("raised bevel border", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = raisedbevel + } + simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + simpleBorders.contents += comp + // addCompForBorder(loweredbevel, "lowered bevel border", simpleBorders) + label = new Label("lowered bevel border", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = loweredbevel + } + simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + simpleBorders.contents += comp + // addCompForBorder(empty, "empty border", simpleBorders) + label = new Label("empty border", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = empty + } + simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + simpleBorders.contents += comp + + //Second pane: matte borders + val matteBorders = new BoxPanel(Orientation.Vertical) { + border = paneEdge + } + val icon: ImageIcon = BorderDemo.createImageIcon("/scala/swing/examples/tutorials/images/wavy.gif", + "wavy-line border icon"); //20x22 + val border0 = Swing.MatteBorder(-1, -1, -1, -1, icon) + if (icon != null) { + // addCompForBorder(border, "matte border (-1,-1,-1,-1,icon)", matteBorders) + label = new Label("matte border (-1,-1,-1,-1,icon)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = border0 + } + matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + matteBorders.contents += comp + } else { + // addCompForBorder(border, "matte border (-1,-1,-1,-1,)", matteBorders) + label = new Label("matte border (-1,-1,-1,-1,)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = border0 + } + } + val border1 = Swing.MatteBorder(1, 5, 1, 1, Color.red) + // addCompForBorder(border1, "matte border (1,5,1,1,Color.red)", matteBorders) + label = new Label("matte border (1,5,1,1,Color.red)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = border1 + } + val border2 = Swing.MatteBorder(0, 20, 0, 0, icon) + if (icon != null) { + // addCompForBorder(border, "matte border (0,20,0,0,icon)", matteBorders) + label = new Label("matte border (0,20,0,0,icon)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = border2 + } + matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + matteBorders.contents += comp + } else { + // addCompForBorder(border, "matte border (0,20,0,0,)") + label = new Label("matte border (0,20,0,0,)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = border2 + } + matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + matteBorders.contents += comp + } + + //Third pane: titled borders + val titledBorders = new BoxPanel(Orientation.Vertical) { + border = paneEdge + } + val titled1 = Swing.TitledBorder(blackline, "title") + // addCompForTitledBorder(titled1, "titled line border" + " (centered, default pos.)", + // TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, titledBorders) + titled1.setTitleJustification(TitledBorder.CENTER) + titled1.setTitlePosition(TitledBorder.DEFAULT_POSITION) + label = new Label("titled line border (centered, default pos.)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = titled1 + } + titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + titledBorders.contents += comp + val titled2 = Swing.TitledBorder(loweredetched, "title") + // addCompForTitledBorder(titled2, "titled lowered etched border" + " (right just., default pos.)", + // TitledBorder.RIGHT, TitledBorder.DEFAULT_POSITION, titledBorders) + titled2.setTitleJustification(TitledBorder.RIGHT) + titled2.setTitlePosition(TitledBorder.DEFAULT_POSITION) + label = new Label("titled lowered etched border (right just., default pos.)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = titled2 + } + titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + titledBorders.contents += comp + val titled3 = Swing.TitledBorder(loweredbevel, "title") + // addCompForTitledBorder(titled3, "titled lowered bevel border" + " (default just., above top)", + // TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.ABOVE_TOP, titledBorders) + titled3.setTitleJustification(TitledBorder.DEFAULT_JUSTIFICATION) + titled3.setTitlePosition(TitledBorder.ABOVE_TOP) + label = new Label("titled lowered bevel border (default just., above top)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = titled3 + } + titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + titledBorders.contents += comp + val titled4 = Swing.TitledBorder(empty, "title") + // addCompForTitledBorder(titled4, "titled empty border" + " (default just., bottom)", + // TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.BOTTOM, titledBorders) + titled4.setTitleJustification(TitledBorder.DEFAULT_JUSTIFICATION) + titled4.setTitlePosition(TitledBorder.BOTTOM) + label = new Label("titled empty border (default just., bottom)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = titled3 + } + titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + titledBorders.contents += comp + + //Fourth pane: compound borders + val compoundBorders = new BoxPanel(Orientation.Vertical) { + border = paneEdge + } + val redline = Swing.LineBorder(Color.red) + val compound1 = Swing.CompoundBorder(raisedbevel, loweredbevel) + // addCompForBorder(compound1, "compound border (two bevels)", compoundBorders) + label = new Label("compound border (two bevels)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = compound1 + } + compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + compoundBorders.contents += comp + val compound2 = Swing.CompoundBorder(redline, compound1) + // addCompForBorder(compound2, "compound border (add a red outline)", compoundBorders) + label = new Label("compound border (add a red outline)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = compound2 + } + compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + compoundBorders.contents += comp + val titledCompound = Swing.TitledBorder(compound2, "title") + titledCompound.setTitleJustification(TitledBorder.CENTER) + titledCompound.setTitlePosition(TitledBorder.BELOW_BOTTOM) + // addCompForBorder(titledn, "titled compound border" + " (centered, below bottom)") + label = new Label("titled compound border (centered, below bottom)", Swing.EmptyIcon, Alignment.Center) + comp = new GridPanel(1, 1) { + contents += label + border = titledCompound + } + compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) + compoundBorders.contents += comp + val tabbedPane = new TabbedPane() + tabbedPane.pages += new TabbedPane.Page("Simple", simpleBorders) + tabbedPane.pages += new TabbedPane.Page("Matte", matteBorders) + tabbedPane.pages += new TabbedPane.Page("Titled", titledBorders) + tabbedPane.pages += new TabbedPane.Page("Compound", compoundBorders) + tabbedPane.selection.index = 0 + val toolTipText = "Blue Wavy Line border art crew:
   Bill Pauley
   Cris St. Aubyn
   Ben Wronsky
   Nathan Walrath
   Tommy Adams, special consultant" + tabbedPane.peer.setToolTipTextAt(1, toolTipText) + contents += tabbedPane + + // def addCompForTitledBorder(border: TitledBorder, + // description: String, + // justification: Int, + // position: Int, container: Panel): Unit = { + // border.setTitleJustification(justification) + // border.setTitlePosition(position) + // addCompForBorder(border, description, container) + // } + // + // def addCompForBorder(border: Border, + // description: String, container: Panel): (Component, Component) = { + // val label: Label = new Label(description, Swing.EmptyIcon, Alignment.Center) + // val comp: GridPanel = new GridPanel(1, 1) { + // contents += label + // border = border + // } + // container.contents += label + // container.contents += comp + // } + +} + +object BorderDemo { + + def createImageIcon(path: String, description: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + new ImageIcon(imgURL, description) + } else { + System.err.println("Couldn't find file: " + path); + null + } + } + + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "BorderDemo" + //Create and set up the content pane. + val newContentPane = new BorderDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala new file mode 100644 index 00000000..25c65337 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *   - Redistributions of source code must retain the above copyright + *     notice, this list of conditions and the following disclaimer. + * + *   - Redistributions in binary form must reproduce the above copyright + *     notice, this list of conditions and the following disclaimer in the + *     documentation and/or other materials provided with the distribution. + * + *   - Neither the name of Oracle or the names of its + *     contributors may be used to endorse or promote products derived + *     from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked + +/* + * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ButtonDemoProject/src/components/ButtonDemo.java + * + * ButtonDemo.scala requires the following files: + * /scala/swing/examples/tutorials/images/right.gif + * /scala/swing/examples/tutorials/images/middle.gif + * /scala/swing/examples/tutorials/images/left.gif + */ +class ButtonDemo extends FlowPanel { + val leftButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get + val middleButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get + val rightButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get + // + val disable: Button = new Button("Disable middle button") { + icon = leftButtonIcon + verticalTextPosition = Alignment.Center + horizontalTextPosition = Alignment.Leading + mnemonic = event.Key.D + tooltip = "Click this button to disable the middle button." + } + // + val middle: Button = new Button("Middle button") { + icon = middleButtonIcon + verticalTextPosition = Alignment.Bottom + horizontalTextPosition = Alignment.Center + mnemonic = event.Key.M + tooltip = "This middle button does nothing when you click it." + } + // + val enable: Button = new Button("Enable middle button") { + icon = rightButtonIcon + enabled = false + mnemonic = event.Key.E + tooltip = "Click this button to enable the middle button." + } + + contents += disable + contents += middle + contents += enable + + listenTo(disable) + listenTo(enable) + + reactions += { + case ButtonClicked(`enable`) => enableMiddle + case ButtonClicked(`disable`) => disableMiddle + } + + def enableMiddle(): Unit = { + enable.enabled = false + middle.enabled = true + disable.enabled = true + } + def disableMiddle(): Unit = { + enable.enabled = true + middle.enabled = false + disable.enabled = false + } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + val imgURL: java.net.URL = getClass().getResource(path) + val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { + Some(Swing.Icon(imgURL)) + } else { + None + } + img + } + +} + +object ButtonDemo { + + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ButtonDemo" + //Create and set up the content pane. + val newContentPane = new ButtonDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + + javax.swing.SwingUtilities.invokeLater(new Runnable() { + + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala new file mode 100644 index 00000000..86c0a717 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *   - Redistributions of source code must retain the above copyright + *     notice, this list of conditions and the following disclaimer. + * + *   - Redistributions in binary form must reproduce the above copyright + *     notice, this list of conditions and the following disclaimer in the + *     documentation and/or other materials provided with the distribution. + * + *   - Neither the name of Oracle or the names of its + *     contributors may be used to endorse or promote products derived + *     from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.Font + +/* + * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ButtonHtmlDemoProject/src/components/ButtonHtmlDemo.java + * + * ButtonHtmlDemo.scala requires the following files: + * /scala/swing/examples/tutorials/images/right.gif + * /scala/swing/examples/tutorials/images/middle.gif + * /scala/swing/examples/tutorials/images/left.gif + */ +class ButtonHtmlDemo extends FlowPanel { + val leftButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get + val middleButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get + val rightButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get + // + val disable: Button = new Button("

Disable
" + + "middle button") { + icon = leftButtonIcon + verticalTextPosition = Alignment.Center + horizontalTextPosition = Alignment.Leading + mnemonic = event.Key.D + tooltip = "Click this button to disable the middle button." + font = font.deriveFont(Font.PLAIN) + } + disable.font = font + // + val middle: Button = new Button("Middle button") { + icon = middleButtonIcon + verticalTextPosition = Alignment.Bottom + horizontalTextPosition = Alignment.Center + mnemonic = event.Key.M + tooltip = "This middle button does nothing when you click it." + font = disable.font + } + // + val enable: Button = new Button("
Enable
" + + "middle button") { + icon = rightButtonIcon + enabled = false + mnemonic = event.Key.E + tooltip = "Click this button to enable the middle button." + font = disable.font + } + + contents += disable + contents += middle + contents += enable + + listenTo(disable) + listenTo(enable) + + reactions += { + case ButtonClicked(`enable`) => enableMiddle + case ButtonClicked(`disable`) => disableMiddle + } + + def enableMiddle(): Unit = { + enable.enabled = false + middle.enabled = true + disable.enabled = true + } + def disableMiddle(): Unit = { + enable.enabled = true + middle.enabled = false + disable.enabled = false + } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + val imgURL: java.net.URL = getClass().getResource(path) + val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { + Some(Swing.Icon(imgURL)) + } else { + None + } + img + } + +} + +object ButtonHtmlDemo { + + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ButtonHtmlDemo" + //Create and set up the content pane. + val newContentPane = new ButtonHtmlDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala new file mode 100644 index 00000000..baf9dd73 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import scala.swing.event.Key +import java.awt.Font +import javax.swing.ImageIcon +import java.net.URL + +/* + * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CheckBoxDemoProject/src/components/CheckBoxDemo.java + * + * CheckBoxDemo.scala requires 16 image files in the /scala/swing/examples/tutorials/images/geek + * directory: + * geek-----.gif, geek-c---.gif, geek--g--.gif, geek---h-.gif, geek----t.gif, + * geek-cg--.gif, ..., geek-cght.gif. + */ +class CheckboxDemo extends BorderPanel { + /* + * Four accessory choices provide for 16 different + * combinations. The image for each combination is + * contained in a separate image file whose name indicates + * the accessories. The filenames are "geek-XXXX.gif" + * where XXXX can be one of the following 16 choices. + * The "choices" StringBuffer contains the string that + * indicates the current selection and is used to generate + * the file name of the image to display. + + ---- //zero accessories + + c--- //one accessory + -g-- + --h- + ---t + + cg-- //two accessories + c-h- + c--t + -gh- + -g-t + --ht + + -ght //three accessories + c-ht + cg-t + cgh- + + cght //all accessories + */ + + //Create the check boxes. + val chinButton = new CheckBox("Chin") + chinButton.mnemonic = Key.C // .VK_C + chinButton.selected = true + + val glassesButton = new CheckBox("Glasses") + glassesButton.mnemonic = Key.G; + glassesButton.selected = true + + val hairButton = new CheckBox("Hair") + hairButton.mnemonic = Key.H + hairButton.selected = true + + val teethButton = new CheckBox("Teeth") + teethButton.mnemonic = Key.T + teethButton.selected = true + + //Indicates what's on the geek. + val choices: StringBuffer = new StringBuffer("cght") + + //Set up the picture label + val pictureLabel = new Label() + pictureLabel.font = pictureLabel.font.deriveFont(Font.ITALIC) + updatePicture() + + //Put the check boxes in a column in a panel + val checkPanel: GridPanel = new GridPanel(0, 1) { + contents += chinButton + contents += glassesButton + contents += hairButton + contents += teethButton + } + + layout(checkPanel) = BorderPanel.Position.East + layout(pictureLabel) = BorderPanel.Position.Center + border = Swing.EmptyBorder(20, 20, 20, 20) + + //Register a listener for the check boxes. + listenTo(chinButton) + listenTo(glassesButton) + listenTo(hairButton) + listenTo(teethButton) + + reactions += { + case ButtonClicked(`chinButton`) => + choices.setCharAt(0, if (!chinButton.selected) '-' else 'c') + updatePicture() + case ButtonClicked(`glassesButton`) => + choices.setCharAt(1, if (!glassesButton.selected) '-' else 'g') + updatePicture() + case ButtonClicked(`hairButton`) => + choices.setCharAt(2, if (!hairButton.selected) '-' else 'h') + updatePicture() + case ButtonClicked(`teethButton`) => + choices.setCharAt(3, if (!teethButton.selected) '-' else 't') + updatePicture() + } + + def updatePicture(): Unit = { + //Get the icon corresponding to the image. + val s = choices.toString() + val icon: ImageIcon = CheckboxDemo.createImageIcon( + "/scala/swing/examples/tutorials/images/geek/geek-" + + choices.toString() + + ".gif") + pictureLabel.icon = icon + pictureLabel.tooltip = choices.toString() + if (icon == null) { + pictureLabel.text = "Missing Image" + } else { + pictureLabel.text = null + } + } +} + +object CheckboxDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "CheckboxDemo" + //Create and set up the content pane. + val newContentPane = new CheckboxDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala new file mode 100644 index 00000000..36f18246 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.Swing.EmptyIcon +import scala.swing.event.ColorChanged +import java.awt.{ Color, Dimension, Font } + +/* + * Tutorial: How to Use Color Choosers + * http://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ColorChooserDemoProject/src/components/ColorChooserDemo.java + */ +/* ColorChooserDemo.java requires no other files. */ +class ColorChooserDemo extends BorderPanel { + //Set up the banner at the top of the window + val banner = new Label("Welcome to the Tutorial Zone!", EmptyIcon, Alignment.Center) { + foreground = Color.yellow + background = Color.blue + opaque = true + font = new Font("SansSerif", Font.BOLD, 24) + preferredSize = new Dimension(100, 65) + } + + val bannerPanel = new BorderPanel() { + layout(banner) = BorderPanel.Position.Center + border = Swing.TitledBorder(Swing.EmptyBorder, "Banner") + } + + //Set up color chooser for setting text color + val tcc: ColorChooser = new ColorChooser(banner.foreground) { + border = Swing.TitledBorder(Swing.EmptyBorder, "Choose Text Color") + reactions += { + case ColorChanged(_, c) => banner.foreground = c + } + } + + + layout(bannerPanel) = BorderPanel.Position.Center + layout(tcc) = BorderPanel.Position.South +} + +object ColorChooserDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ColorChooserDemo" + //Create and set up the content pane. + val newContentPane = new ColorChooserDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala new file mode 100644 index 00000000..1cb4efd0 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ SelectionChanged } +import java.awt.{ Dimension, Font } +import javax.swing.{ BorderFactory, ImageIcon } +import java.net.URL + +/* + * Tutorial: How to Use Combo Boxes + * http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemoProject/src/components/ComboBoxDemo.java + */ +class ComboBoxDemo extends BorderPanel { + + val petStrings: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig") + + //Create the combo box, select the item at index 4. + //Indices start at 0, so 4 specifies the pig. + val petList = new ComboBox[String](petStrings) { + selection.item = petStrings(4) + } + + //Set up the picture label. + val imgIcon = ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + + petList.selection.item + ".gif") + val picture = new Label() { + icon = imgIcon + font = font.deriveFont(Font.ITALIC) + horizontalAlignment = Alignment.Center + //The preferred size is hard-coded to be the width of the + //widest image and the height of the tallest image + the border. + //A real program would compute this. + preferredSize = new Dimension(177, 122 + 10) + } + updateLabel(petList.selection.item) + + layout(petList) = BorderPanel.Position.East + layout(picture) = BorderPanel.Position.Center + border = BorderFactory.createEmptyBorder(20, 20, 20, 20) + + listenTo(petList.selection) + reactions += { + case SelectionChanged(`petList`) => updateLabel(petList.selection.item) + } + + def updateLabel(s: String): Unit = { + val ic = ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + s + ".gif") + picture.icon = ic + } +} + +object ComboBoxDemo { + val birdString = "Bird" + val catString = "Cat" + val dogString = "Dog" + val rabbitString = "Rabbit" + val pigString = "Pig" + + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ComboBoxDemo" + //Create and set up the content pane. + val newContentPane = new ComboBoxDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala new file mode 100644 index 00000000..2f96dfde --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.SelectionChanged +import java.awt.Color +import java.util.Date +import java.text.SimpleDateFormat + +/* + * Tutorial: How to Use Combo Boxes + * http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemo2Project/src/components/ComboBoxDemo2.java + */ +/* ComboBoxDemo2.java requires no other files. */ +class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { + val patternExamples = Array[String]( + "dd MMMMM yyyy", + "dd.MM.yy", + "MM/dd/yy", + "yyyy.MM.dd G 'at' hh:mm:ss z", + "EEE, MMM d, ''yy", + "h:mm a", + "H:mm:ss:SSS", + "K:mm a,z", + "yyyy.MMMMM.dd GGG hh:mm aaa") + + + //Set up the UI for selecting a pattern. + val patternLabel1 = new Label("Enter the pattern string or") + val patternLabel2 = new Label("select one from the list:") + val patternList = new ComboBox[String](patternExamples) { + peer.setEditable(true) + // editable = true + selection.item = patternExamples(0) + } + + //Create the UI for displaying result. + val resultLabel = new Label("Current Date/Time", Swing.EmptyIcon, Alignment.Left ) { + foreground = Color.black + border = Swing.EmptyBorder(5, 5, 5, 5) + } + + val result = new Label(" ") { + foreground = Color.black + border = Swing.CompoundBorder( + Swing.LineBorder(Color.black), + Swing.EmptyBorder(5,5,5,5) + ) + } + + val patternPanel = new BoxPanel(Orientation.Vertical) { + contents += patternLabel1 + contents += patternLabel2 + // xAlignment = Alignment.Left + peer.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT) + contents += patternList + } + + val resultPanel = new GridPanel(0,1) { + contents += resultLabel + contents += result + // xAlignment = Alignment.Left + peer.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT) + } + + contents += patternPanel + contents += resultPanel + border = Swing.EmptyBorder(10,10,10,10) + reformat() + + listenTo(patternList.selection) + reactions += { + case SelectionChanged(`patternList`) => // currentPattern = patternList.selection.item + reformat() + } + + def reformat(): Unit = { + val today = new Date() + val formatter = new SimpleDateFormat(patternList.selection.item) + try { + val dateString = formatter.format(today) + result.foreground = Color.black + result.text = dateString + } + catch { + case iae: IllegalArgumentException => result.foreground = Color.red + result.text = "Error: " + iae.getMessage() + } + } +} + +object ComboBoxDemo2 { + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ComboBoxDemo2" + //Create and set up the content pane. + val newContentPane = new ComboBoxDemo2(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala new file mode 100644 index 00000000..a81a81af --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import java.awt.{ Color, Graphics } + +class Corner extends java.awt.Component { + def paintComponent(g: Graphics): Unit = { + // Fill me with dirty brown/orange. + g.setColor(new Color(230, 163, 4)) + g.fillRect(0, 0, getWidth().toInt, getHeight().toInt) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala new file mode 100644 index 00000000..59cdf9d5 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import javax.swing.ImageIcon +import java.net.URL +import java.awt.{ Dimension, Font } + +/* + * Tutorial: How to Use Combo Boxes + * http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CustomComboBoxDemoProject/src/components/CustomComboBoxDemo.java + * + * CustomComboBoxDemo.scala uses the following files: + * /scala/swing/examples/tutorials/images/Bird.gif + * /scala/swing/examples/tutorials/images/Cat.gif + * /scala/swing/examples/tutorials/images/Dog.gif + * /scala/swing/examples/tutorials/images/Rabbit.gif + * /scala/swing/examples/tutorials/images/Pig.gif + */ +class CustomComboBoxDemo extends BorderPanel { + val petStrings: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig") + val images: Array[ImageIcon] = new Array[ImageIcon](petStrings.length) + val intArray: Array[Int] = new Array[Int](petStrings.length) + /* + * Despite its use of EmptyBorder, this panel makes a fine content + * pane because the empty border just increases the panel's size + * and is "painted" on top of the panel's normal background. In + * other words, the JPanel fills its entire background if it's + * opaque (which it is by default); adding a border doesn't change + * that. + */ + for (i <- 0 until petStrings.length) { + images(i) = CustomComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + petStrings(i) + ".gif"); + if (images(i) != null) { + images(i).setDescription(petStrings(i)) + } + intArray(i) = i + } + + //Create the combo box. + val petList = new ComboBox[Int](intArray) { + renderer = new ComboBoxRenderer() + preferredSize = new Dimension(200, 130) + peer.setMaximumRowCount(3) + } + + //Lay out the demo. + layout(petList) = BorderPanel.Position.North + border = Swing.EmptyBorder(20, 20, 20, 20) + + class ComboBoxRenderer extends ListView.AbstractRenderer[Int, Label](new Label("")) { + var uhOhFont: Option[Font] = None + /* + * This method finds the image and text corresponding + * to the selected value and returns the label, set up + * to display the text and image. + */ + def configure( + listMe: ListView[_], + isSelected: Boolean, + cellHasFocus: Boolean, + a: Int, + index: Int) = { + //Set the icon and text. If icon was null, say so. + component.icon = images(a) + val pet = petStrings(a) + if (component.icon != null) { + component.text = pet; + component.font = listMe.font + } else { + setUhOhText(pet + " (no image available)", + listMe.font) + } + } + + //Set the font and text when no image was found. + def setUhOhText(uhOhText: String, normalFont: Font) = { + if (!uhOhFont.isDefined) { //lazily create this font + uhOhFont = Some(normalFont.deriveFont(Font.ITALIC)) + } + component.font = uhOhFont.get + component.text = uhOhText + } + } +} + +object CustomComboBoxDemo { + + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "CustomComboBoxDemo" + //Create and set up the content pane. + val newContentPane = new CustomComboBoxDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala new file mode 100644 index 00000000..f013492a --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -0,0 +1,529 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import scala.swing.TabbedPane.Page +import javax.swing.border.Border +import java.net.URL +import javax.swing.ImageIcon +import java.awt.{ Dimension, Font } + +/* + * Tutorial: How to Use Dialogs + * http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/DialogDemoProject/src/components/DialogDemo.java + * + * DialogDemo.scala requires these files: + * CustomDialog.scala + * /scala/swing/examples/tutorials/images/middle.gif + */ +class DialogDemo(val frame: Frame) extends BorderPanel { + val icon: ImageIcon = DialogDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val simpleDialogDesc = "Some simple message dialogs" + val iconDesc = "A JOptionPane has its choice of icons" + val moreDialogDesc = "Some more dialogs" + // val customDialog = new CustomDialog(frame, "geisel", this) + + val padding: Border = Swing.EmptyBorder(20, 20, 5, 20) + //Create the components. + val label: Label = new Label("Click the \"Show it!\" button" + + " to bring up the selected dialog.", Swing.EmptyIcon, Alignment.Center) { + border = Swing.EmptyBorder(10, 10, 10, 10) + } + val frequentPanel = createSimpleDialogBox() + frequentPanel.border = padding + val featurePanel = createFeatureDialogBox() + featurePanel.border = padding + val iconPanel = createIconDialogBox() + iconPanel.border = padding + + //Lay them out. + val tabbedPane = new TabbedPane() + tabbedPane.pages += new Page("Simple Modal Dialogs", frequentPanel, simpleDialogDesc) + tabbedPane.pages += new Page("More Dialogs", featurePanel, moreDialogDesc) + tabbedPane.pages += new Page("Dialog Icons", iconPanel, iconDesc) + + layout(tabbedPane) = BorderPanel.Position.Center + layout(label) = BorderPanel.Position.South + + /** Sets the text displayed at the bottom of the frame. */ + def setLabel(newText: String): Unit = { + label.text = newText + } + /** Creates the panel shown by the first tab. */ + private def createSimpleDialogBox(): BorderPanel = { + val numButtons = 4 + val radioButtons: Array[RadioButton] = new Array[RadioButton](numButtons) + + val showItButton: Button = new Button("Show it!") + + val defaultMessageCommand = "default" + val yesNoCommand = "yesno" + val yeahNahCommand = "yeahnah" + val yncCommand = "ync" + + val group: ButtonGroup = new ButtonGroup() { + + } + + radioButtons(0) = new RadioButton("OK (in the L&F's words)") { + selected = true + } + + // radioButtons[0].setActionCommand(defaultMessageCommand) + + radioButtons(1) = new RadioButton("Yes/No (in the L&F's words)") + // radioButtons[1].setActionCommand(yesNoCommand) + + radioButtons(2) = new RadioButton("Yes/No " + + "(in the programmer's words)") + // radioButtons[2].setActionCommand(yeahNahCommand) + + radioButtons(3) = new RadioButton("Yes/No/Cancel " + + "(in the programmer's words)") + // radioButtons[3].setActionCommand(yncCommand) + + val defaultMessageCommandButton = radioButtons(0) + val yesNoCommandButton = radioButtons(1) + val yeahNahCommandButton = radioButtons(2) + val yncCommandButton = radioButtons(3) + + for (i <- 0 until numButtons) { + group.buttons += radioButtons(i) + } + + var actionCommand = defaultMessageCommand + listenTo(showItButton) + listenTo(defaultMessageCommandButton) + listenTo(yesNoCommandButton) + listenTo(yeahNahCommandButton) + listenTo(yncCommandButton) + reactions += { + case ButtonClicked(`defaultMessageCommandButton`) => + actionCommand = defaultMessageCommand + case ButtonClicked(`yesNoCommandButton`) => + actionCommand = yesNoCommand + case ButtonClicked(`yeahNahCommandButton`) => + actionCommand = yeahNahCommand + case ButtonClicked(`yncCommandButton`) => + actionCommand = yncCommand + case ButtonClicked(`showItButton`) => + actionCommand match { + //ok dialog + case "default" => + val command: String = defaultMessageCommand + Dialog.showMessage(this, + "Eggs aren't supposed to be green.") + //yes/no dialog + case "yesno" => + val n = Dialog.showConfirmation( + this, "Would you like green eggs and ham?", + "An Inane Question", + Dialog.Options.YesNo) + + if (n == Dialog.Result.Yes) { + setLabel("Ewww!"); + } else if (n == Dialog.Result.No) { + setLabel("Me neither!"); + } else { + setLabel("Come on -- tell me!"); + } + //yes/no (not in those words) + case "yeahnah" => + val options: Array[String] = Array("Yes, please", "No way!") + val n = Dialog.showOptions(this, + "Would you like green eggs and ham?", + "A Silly Question", + Dialog.Options.YesNo, + Dialog.Message.Question, + Swing.EmptyIcon, + options, + 0) + if (n == Dialog.Result.Yes) { + setLabel("You're kidding!") + } else if (n == Dialog.Result.No) { + setLabel("I don't like them, either.") + } else { + setLabel("Come on -- 'fess up!") + } + //yes/no/cancel (not in those words) + case "ync" => + val options: Array[String] = Array("Yes, please", + "No, thanks", + "No eggs, no ham!") + val n = Dialog.showOptions(this, + "Would you like some green eggs to go " + + "with that ham?", + "A Silly Question", + Dialog.Options.YesNoCancel, + Dialog.Message.Question, + null, + options, + 2) + if (n == Dialog.Result.Yes) { + setLabel("Here you go: green eggs and ham!") + } else if (n == Dialog.Result.No) { + setLabel("OK, just the ham, then.") + } else if (n == Dialog.Result.Cancel) { + setLabel("Well, I'm certainly not going to eat them!") + } else { + setLabel("Please tell me what you want!") + } + } + } + createPane(simpleDialogDesc + ":", + radioButtons, + showItButton) + } + + /** + * Used by createSimpleDialogBox and createFeatureDialogBox + * to create a pane containing a description, a single column + * of radio buttons, and the Show it! button. + */ + private def createPane(description: String, + radioButtons: Array[RadioButton], + showButton: Button): BorderPanel = { + + val numChoices = radioButtons.length + val label = new Label(description) + val box: BoxPanel = new BoxPanel(Orientation.Vertical) { + contents += label + } + + for (i <- 0 until numChoices) { + box.contents += radioButtons(i); + } + + val pane = new BorderPanel() { + layout(box) = BorderPanel.Position.North + layout(showButton) = BorderPanel.Position.South + } + pane + } + + /** + * Like createPane, but creates a pane with 2 columns of radio + * buttons. The number of buttons passed in *must* be even. + */ + private def create2ColPane(description: String, + radioButtons: Array[RadioButton], + showButton: Button): BorderPanel = { + val label = new Label(description) + val numPerColumn = radioButtons.length / 2 + val grid = new GridPanel(numPerColumn, 2) + for (i <- 0 until radioButtons.length) { + grid.contents += radioButtons(i) + } + val box = new BoxPanel(Orientation.Vertical) { + contents += label + grid.xLayoutAlignment = 0.0f + contents += grid + } + val pane = new BorderPanel() { + layout(box) = BorderPanel.Position.North + layout(showButton) = BorderPanel.Position.South + } + pane + } + /* + * Creates the panel shown by the 3rd tab. + * These dialogs are implemented using showMessageDialog, but + * you can specify the icon (using similar code) for any other + * kind of dialog, as well. + */ + def createIconDialogBox(): BorderPanel = { + val numButtons = 6 + val radioButtons: Array[RadioButton] = new Array[RadioButton](numButtons) + val plainCommand = "plain" + val infoCommand = "info" + val questionCommand = "question" + val errorCommand = "error" + val warningCommand = "warning" + val customCommand = "custom" + radioButtons(0) = new RadioButton("Plain (no icon)") { + selected = true + } + val plainCommandButton = radioButtons(0) + radioButtons(1) = new RadioButton("Information icon") + val infoCommandButton = radioButtons(1) + radioButtons(2) = new RadioButton("Question icon") + val questionCommandButton = radioButtons(2) + radioButtons(3) = new RadioButton("Error icon") + val errorCommandButton = radioButtons(3) + radioButtons(4) = new RadioButton("Warning icon") + val warningCommandButton = radioButtons(4) + radioButtons(5) = new RadioButton("Custom icon") + val customCommandButton = radioButtons(5) + + val group: ButtonGroup = new ButtonGroup() { + for (i <- 0 until numButtons) { + buttons += radioButtons(i) + } + } + val showItButton = new Button("Show it!") + var actionCommand = plainCommand + listenTo(plainCommandButton) + listenTo(infoCommandButton) + listenTo(questionCommandButton) + listenTo(errorCommandButton) + listenTo(warningCommandButton) + listenTo(customCommandButton) + listenTo(showItButton) + reactions += { + case ButtonClicked(`plainCommandButton`) => actionCommand = plainCommand + case ButtonClicked(`infoCommandButton`) => actionCommand = infoCommand + case ButtonClicked(`questionCommandButton`) => actionCommand = questionCommand + case ButtonClicked(`errorCommandButton`) => actionCommand = errorCommand + case ButtonClicked(`warningCommandButton`) => actionCommand = warningCommand + case ButtonClicked(`customCommandButton`) => actionCommand = customCommand + case ButtonClicked(`showItButton`) => + actionCommand match { + //no icon + case "plain" => + Dialog.showMessage(this, + "Eggs aren't supposed to be green.", + "A plain message", + Dialog.Message.Plain) + //information icon + case "info" => + Dialog.showMessage(this, + "Eggs aren't supposed to be green.", + "Inane informational dialog", + Dialog.Message.Info) + //question icon + case "question" => + Dialog.showMessage(this, + "You shouldn't use a message dialog " + + "(like this)\n" + + "for a question, OK?", + "Inane question", + Dialog.Message.Question) + //error icon + case "error" => + Dialog.showMessage(this, + "Eggs aren't supposed to be green.", + "Inane error", + Dialog.Message.Error) + //warning icon + case "warning" => + Dialog.showMessage(this, + "Eggs aren't supposed to be green.", + "Inane warning", + Dialog.Message.Warning) + //custom icon + case "custom" => + Dialog.showMessage(this, + "Eggs aren't supposed to be green.", + "Inane custom dialog", + Dialog.Message.Info, + icon) + } + } + create2ColPane(iconDesc + ":", radioButtons, showItButton) + } + + /** Creates the panel shown by the second tab. */ + private def createFeatureDialogBox(): BorderPanel = { + val numButtons = 5 + val radioButtons: Array[RadioButton] = new Array[RadioButton](numButtons) + val pickOneCommand = "pickone" + val textEnteredCommand = "textfield" + val nonAutoCommand = "nonautooption" + val customOptionCommand = "customoption" + val nonModalCommand = "nonmodal" + radioButtons(0) = new RadioButton("Pick one of several choices") { + selected = true + } + val pickOneCommandButton = radioButtons(0) + radioButtons(1) = new RadioButton("Enter some text") + val textEnteredCommandButton = radioButtons(1) + radioButtons(2) = new RadioButton("Non-auto-closing dialog") + val nonAutoCommandButton = radioButtons(2) + radioButtons(3) = new RadioButton("Input-validating dialog " + + "(with custom message area)") + val customOptionCommandButton = radioButtons(3) + radioButtons(4) = new RadioButton("Non-modal dialog") + val nonModalCommandButton = radioButtons(4) + + val group: ButtonGroup = new ButtonGroup() { + for (i <- 0 until numButtons) { + buttons += radioButtons(i) + } + } + val showItButton = new Button("Show it!") + var actionCommand = pickOneCommand + listenTo(pickOneCommandButton) + listenTo(textEnteredCommandButton) + listenTo(nonAutoCommandButton) + listenTo(customOptionCommandButton) + listenTo(nonModalCommandButton) + listenTo(showItButton) + reactions += { + case ButtonClicked(`pickOneCommandButton`) => actionCommand = pickOneCommand + case ButtonClicked(`textEnteredCommandButton`) => actionCommand = textEnteredCommand + case ButtonClicked(`nonAutoCommandButton`) => actionCommand = nonAutoCommand + case ButtonClicked(`customOptionCommandButton`) => actionCommand = customOptionCommand + case ButtonClicked(`nonModalCommandButton`) => actionCommand = nonModalCommand + case ButtonClicked(`showItButton`) => + actionCommand match { + //pick one of many + case "pickone" => + val possibilities = Array("ham", "spam", "yam") + val s: Option[String] = Dialog.showInput[String](this, + "Complete the sentence:\n" + + "\"Green eggs and...\"", + "Customized Dialog", + Dialog.Message.Plain, + icon, + possibilities, + "ham") + if (s.isDefined && s.get.length > 0) { + setLabel("Green eggs and..." + s.get + "!") + } else { + setLabel("Come on, finish the sentence!") + } + //text input + case "textfield" => + val s: Option[String] = Dialog.showInput[String](this, + "Complete the sentence:\n" + + "\"Green eggs and...\"", + "Customized Dialog", + Dialog.Message.Plain, + icon, + Nil, + "ham") + if (s.isDefined && s.get.length > 0) { + setLabel("Green eggs and..." + s.get + "!") + } else { + setLabel("Come on, finish the sentence!") + } + //non-auto-closing dialog + case "nonautooption" => + setLabel("Not supported.") + //non-auto-closing dialog with custom message area + //NOTE: if you don't intend to check the input, + //then just use showInputDialog instead. + case "customoption" => + setLabel("Not supported.") + //non-modal dialog + case "nonmodal" => + val dialog = new Dialog(frame, frame.peer.getGraphicsConfiguration()) { + title = "A Non-Modal Dialog" + + val label: Label = new Label("

" + + "This is a non-modal dialog.
" + + "You can have one or more of these up
" + + "and still use the main window.") { + horizontalAlignment = Alignment.Center + val myFont = font + font = myFont.deriveFont(Font.PLAIN, 14.0f) + } + val closeButton: Button = new Button("Close") + + val closePanel = new BoxPanel(Orientation.Horizontal) { + contents += Swing.HGlue + contents += closeButton + border = Swing.EmptyBorder(0, 0, 5, 5) + } + + val contentPane: BorderPanel = new BorderPanel() { + layout(label) = BorderPanel.Position.Center + layout(closePanel) = BorderPanel.Position.South + opaque = true + } + contents = contentPane + listenTo(closeButton) + reactions += { + case ButtonClicked(`closeButton`) => + visible = false + dispose() + } + } + dialog.size = new Dimension(300, 150) + dialog.peer.setLocationRelativeTo(frame.peer) + dialog.visible = true + } + } + createPane(moreDialogDesc + ":", radioButtons, showItButton) + } + +} + +object DialogDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame = new Frame() { + title = "DialogDemo" + + //Create and set up the content pane. + val contentPane: DialogDemo = new DialogDemo(this) + contentPane.opaque = true + contents = contentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala new file mode 100644 index 00000000..9a450af4 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import java.awt.Toolkit +import javax.swing.text.{ AttributeSet, DocumentFilter } + +/* A 1.4 class used by TextComponentDemo.java. */ + +class DocumentSizeFilter(val maxCharacters: Int) extends DocumentFilter { + val Debug: Boolean = false + + override def insertString(fb: DocumentFilter.FilterBypass, offs: Int, str: String, a: AttributeSet): Unit = { + //This rejects the entire insertion if it would make + //the contents too long. Another option would be + //to truncate the inserted string so the contents + //would be exactly maxCharacters in length. + if ((fb.getDocument().getLength() + str.length) <= maxCharacters) { + super.insertString(fb, offs, str, a) + } else { + Toolkit.getDefaultToolkit().beep() + } + } + + def replaceString(fb: DocumentFilter.FilterBypass, offs: Int, length: Int, str: String, a: AttributeSet): Unit = { + if (Debug) { + println("in DocumentSizeFilter's replace method") + } + //This rejects the entire replacement if it would make + //the contents too long. Another option would be + //to truncate the replacement string so the contents + //would be exactly maxCharacters in length. + if ((fb.getDocument().getLength() + str.length - length) <= maxCharacters) { + super.replace(fb, offs, length, str, a) + } else { + Toolkit.getDefaultToolkit().beep() + } + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala new file mode 100644 index 00000000..40d6e0e5 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event._ + +import java.io.File + +/* + * Tutorial: How to Use File Choosers + * http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FileChooserDemoProject/src/components/FileChooserDemo.java + * + * FileChooserDemo.scala uses these files: + * /scala/swing/examples/tutorials/images/Open16.gif + * /scala/swing/examples/tutorials/images/Save16.gif + */ +object FileChooserDemo extends SimpleSwingApplication { + private val newline = "\n" + + val log = new TextArea(5, 20) + log.peer.setMargin(new Insets(5, 5, 5, 5)) + log.editable = false + val logScrollPane = new ScrollPane(log) + + //Create a file chooser + val fc = new FileChooser() + + //Uncomment one of the following lines to try a different + //file selection mode. The first allows just directories + //to be selected (and, at least in the Java look and feel, + //shown). The second allows both files and directories + //to be selected. If you leave these lines commented out, + //then the default mode (FILES_ONLY) will be used. + // + //fc.fileSelectionMode = FileChooser.SelectionMode.DirectoriesOnly + //fc.fileSelectionMode = FileChooser.SelectionMode.FilesAndDirectories + //fc.fileSelectionMode = FileChooser.SelectionMode.FilesOnly + + //Create the open button. We use the image from the JLF + //Graphics Repository (but we extracted it from the jar). + val openButton = new Button("Open a File...") + val openIconURL:java.net.URL = getClass().getResource("/scala/swing/examples/tutorials/images/Open16.gif") + if (openIconURL != null) { + openButton.icon = Swing.Icon(openIconURL) + } + + //Create the save button. We use the image from the JLF + //Graphics Repository (but we extracted it from the jar). + val saveButton = new Button("Save a File...") + val saveIconURL:java.net.URL = getClass().getResource("/scala/swing/examples/tutorials/images/Save16.gif") + if (saveIconURL != null) { + saveButton.icon = Swing.Icon(saveIconURL) + } + + //For layout purposes, put the buttons in a separate panel + val buttonPanel = new FlowPanel() { + contents += openButton + contents += saveButton + } + + def top = new MainFrame { + title = "FileChooserDemo" + val bp = new BorderPanel { + layout(buttonPanel) = BorderPanel.Position.North + layout(logScrollPane) = BorderPanel.Position.Center + } + contents = bp + listenTo(openButton) + listenTo(saveButton) + val prefix = "You typed \"" + reactions += { + case ButtonClicked(`openButton`) => + if (fc.showOpenDialog(buttonPanel) == FileChooser.Result.Approve) { + val file: File = fc.selectedFile + //This is where a real application would open the file. + log.append("Opening: " + file.getName() + "." + newline) + } + else { + log.append("Open command cancelled by user." + newline) + } + case ButtonClicked(`saveButton`) => + if (fc.showOpenDialog(buttonPanel) == FileChooser.Result.Approve) { + val file: File = fc.selectedFile + //This is where a real application would save the file. + log.append("Saving: " + file.getName() + "." + newline) + } + else { + log.append("Save command cancelled by user." + newline) + } + } + } + +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala new file mode 100644 index 00000000..1870efed --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala @@ -0,0 +1,197 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.text.NumberFormat +import java.awt.Color + +/* + * Tutorial: How to Use Formatted Text Fields + * http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FormattedTextFieldDemoProject/src/components/FormattedTextFieldDemo.java + * + * FormattedTextFieldDemo.scala requires no other files. + * + * It implements a mortgage calculator that uses four JFormattedTextFields. + */ +class FormattedTextFieldDemo extends BorderPanel { + + //Values for the fields + private val amount: Double = 100000 + private val rate: Double = 7.5 //7.5% + private val numPeriods: Int = 30 + + //Labels to identify the fields + // private JLabel amountLabel + // private JLabel rateLabel + // private JLabel numPeriodsLabel + // private JLabel paymentLabel + + //Strings for the labels + private val amountString = "Loan Amount: " + private val rateString = "APR (%): " + private val numPeriodsString = "Years: " + private val paymentString = "Monthly Payment: " + + //Fields for data entry + // private JFormattedTextField amountField; + // private JFormattedTextField rateField; + // private JFormattedTextField numPeriodsField; + // private JFormattedTextField paymentField; + + //Formats to format and parse numbers + private val amountFormat: NumberFormat = NumberFormat.getNumberInstance() + private val percentFormat: NumberFormat = NumberFormat.getNumberInstance() + percentFormat.setMinimumFractionDigits(3) + private val paymentFormat: NumberFormat = NumberFormat.getCurrencyInstance() + + val payment = computePayment(amount, + rate, + numPeriods) + //Create the labels. + val amountLabel = new Label(amountString) + val rateLabel = new Label(rateString) + // val numPeriodsLabel = new Label(numPeriodsString) + val paymentLabel = new Label(paymentString) + + //Create the text fields and set them up. + val amountField = new FormattedTextField(amountFormat) { + // There are no instances of FormattedTextField that work... + // value = amount + // columns = 10 + } + val rateField = new FormattedTextField(percentFormat) { + // There are no instances of FormattedTextField that work... + // value = rate + // columns = 10 + } + // Format is obligatory in the scala constructors + // val numPeriodsField = new FormattedTextField() { + // There are no instances of FormattedTextField that work... + // value = numPeriods + // columns = 10 + // } + val paymentField = new FormattedTextField(paymentFormat) { + // There are no instances of FormattedTextField that work... + // value = payment + // columns = 10 + editable = false + foreground = Color.red + } + + //Tell accessibility tools about label/textfield pairs. + amountLabel.peer.setLabelFor(amountField.peer) + rateLabel.peer.setLabelFor(rateField.peer) + // numPeriodsLabel.peer.setLabelFor(numPeriodsField.peer) + paymentLabel.peer.setLabelFor(paymentField.peer) + + //Layout the labels in a panel + val labelPane = new GridPanel(0, 1) { + contents += amountLabel + contents += rateLabel + // contents += numPeriodsLabel + contents += paymentLabel + } + + //Layout the text fields in a panel. + val fieldPane = new GridPanel(0, 1) { + contents += amountField + contents += rateField + // contents += numPeriodsField + contents += paymentField + } + + //Put the panels in this panel, labels on left, + //text fields on right. + border = Swing.EmptyBorder(20, 20, 20, 20) + layout(labelPane) = BorderPanel.Position.Center + layout(fieldPane) = BorderPanel.Position.South + + listenTo(amountField) + listenTo(rateField) + // listenTo(numPeriodsField) +//What is the analogue of a PropertyChangeEvent? +// reactions += { +// } + + //Compute the monthly payment based on the loan amount, + //APR, and length of loan. + def computePayment(loanAmt: Double, rate: Double, numPeriodsYear: Int): Double = { + val numPeriods = 12 * numPeriodsYear //get number of months + val denominator = if (rate > 0.01) { + val I = rate / 100.0 / 12.0 //get monthly rate from annual + val partial1 = Math.pow((1 + I), (0.0 - numPeriods)) + (1 - partial1) / I + } else { //rate ~= 0 + numPeriods + } + (-1 * loanAmt) / denominator + } +} + +object FormattedTextFieldDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame = new Frame() { + title = "FormattedTextFieldDemo" + + //Create and set up the content pane. + val contentPane: FormattedTextFieldDemo = new FormattedTextFieldDemo() + contentPane.opaque = true + contents = contentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala new file mode 100644 index 00000000..87f865b7 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.awt.Dimension + +/* + * Tutorial: How to Make Frames (Main Windows) + * http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemoProject/src/components/FrameDemo.java + * + * FrameDemo.scala requires no other files. + */ +object FrameDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val label = new Label("") { + preferredSize = new Dimension(175, 100) + } + //Create and set up the window. + val frame = new Frame() { + title = "FrameDemo" + contents = new BorderPanel() { + layout(label) = BorderPanel.Position.Center + } + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + //The standard main method. + def main(args: Array[String]): Unit = { + //Schedule a job for the event dispatch thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }); + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala new file mode 100644 index 00000000..cad461d9 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -0,0 +1,328 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import javax.swing.{ Box, BoxLayout, JDialog, JFrame, ImageIcon, UIManager } +import java.awt.{ BorderLayout, Color, Component, Dimension, Graphics, Image, Point, Toolkit } +import java.awt.image.BufferedImage +import java.net.URL + +/* + * Tutorial: How to Make Frames (Main Windows) + * http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemo2Project/src/components/FrameDemo2.java + * + * FrameDemo2.scala shows off the window decoration features added in + * 1.4, plus some window positioning code and (optionally) + * setIconImage. It uses the file /scala/swing/examples/tutorials/images/FD.jpg. + */ +class FrameDemo2 { + private var lastLocation: Point = null + private var defaultButton: Button = null + // private val maxX = 500 + // private val maxY = 500 + //constants for action commands + val NO_DECORATIONS = "no_dec"; + val LF_DECORATIONS = "laf_dec"; + val WS_DECORATIONS = "ws_dec"; + val CREATE_WINDOW = "new_win"; + val DEFAULT_ICON = "def_icon"; + val FILE_ICON = "file_icon"; + val PAINT_ICON = "paint_icon"; + + //true if the next frame created should have no window decorations + var noDecorations = false; + + //true if the next frame created should have setIconImage called + var specifyIcon = false; + + //true if the next frame created should have a custom painted icon + var createIcon = false; + + val screenSize: Dimension = Toolkit.getDefaultToolkit().getScreenSize() + val maxX = screenSize.width - 50 + val maxY = screenSize.height - 50 + + //Create a new MyFrame object and show it. + def showNewWindow(): Unit = { + val frame = new MyFrame() + //Take care of the no window decorations case. + //NOTE: Unless you really need the functionality + //provided by JFrame, you would usually use a + //Window or JWindow instead of an undecorated JFrame. + if (noDecorations) { + frame.peer.setUndecorated(true); + } + + //Set window location. + if (lastLocation != null) { + //Move the window over and down 40 pixels. + lastLocation.translate(40, 40); + if ((lastLocation.x > maxX) || (lastLocation.y > maxY)) { + lastLocation.setLocation(0, 0); + } + frame.location = lastLocation + } else { + lastLocation = frame.location + } + + //Calling setIconImage sets the icon displayed when the window + //is minimized. Most window systems (or look and feels, if + //decorations are provided by the look and feel) also use this + //icon in the window decorations. + if (specifyIcon) { + if (createIcon) { + //create an icon from scratch + frame.iconImage = FrameDemo2.createFDImage() + } else { + //get the icon from a file + frame.iconImage = FrameDemo2.getFDImage() + } + } + + } + + // Create the window-creation controls that go in the main window. + def createOptionControls(frame: Frame): Box = { + val label1 = new Label("Decoration options for subsequently created frames:") + val bg1 = new ButtonGroup() + val label2 = new Label("Icon options:") + val bg2 = new ButtonGroup() + + //Create the buttons + val rb1 = new RadioButton() { + text = "Look and feel decorated" + selected = true + } + bg1.buttons += rb1 + // + val rb2 = new RadioButton() { + text = "Window system decorated" + } + bg1.buttons += rb2 + // + val rb3 = new RadioButton() { + text = "No decorations" + } + bg1.buttons += rb3 + // + val rb4 = new RadioButton() { + text = "Default icon" + selected = true + } + bg2.buttons += rb4 + // + val rb5 = new RadioButton() { + text = "Icon from a JPEG file" + } + bg2.buttons += rb5 + // + val rb6 = new RadioButton() { + text = "Painted icon" + } + bg2.buttons += rb6 + + //Add everything to a container. + val box = Box.createVerticalBox() + box.add(label1.peer) + box.add(Swing.VStrut(5).peer) // spacer + box.add(rb1.peer) + box.add(rb2.peer) + box.add(rb3.peer) + // + box.add(Swing.VStrut(15).peer) // spacer + box.add(label2.peer) + box.add(Swing.VStrut(5).peer) // spacer + box.add(rb4.peer) + box.add(rb5.peer) + box.add(rb6.peer) + + //Add some breathing room. + box.setBorder(Swing.EmptyBorder(10, 10, 10, 10)) + + frame.listenTo(rb1) + frame.listenTo(rb2) + frame.listenTo(rb3) + frame.listenTo(rb4) + frame.listenTo(rb5) + frame.listenTo(rb6) + frame.reactions += { + case ButtonClicked(`rb1`) => + noDecorations = false + JFrame.setDefaultLookAndFeelDecorated(true) + case ButtonClicked(`rb2`) => + noDecorations = false + JFrame.setDefaultLookAndFeelDecorated(false) + case ButtonClicked(`rb3`) => + noDecorations = true + JFrame.setDefaultLookAndFeelDecorated(false) + case ButtonClicked(`rb4`) => specifyIcon = false + case ButtonClicked(`rb5`) => + specifyIcon = true + createIcon = false + case ButtonClicked(`rb6`) => + specifyIcon = true + createIcon = true + } + + box + } + + //Create the button that goes in the main window. + def createButtonPane(frame: Frame): javax.swing.JComponent = { + val button = new Button("New window") + defaultButton = button + + frame.listenTo(button) + frame.reactions += { + case ButtonClicked(`button`) => showNewWindow() + } + + //Center the button in a panel with some space around it. + val pane = new FlowPanel() { + border = Swing.EmptyBorder(5, 5, 5, 5) + contents += button + } + pane.peer + } + +} + +class MyFrame extends Frame { + title = "A window" + + //This button lets you close even an undecorated window. + val button = new Button("Close window") + + //Place the button near the bottom of the window. + //Undecorated windows are not supported in scala swing. Go to the peer. + val contentPane: java.awt.Container = peer.getContentPane() + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.PAGE_AXIS)) + contentPane.add(Box.createVerticalGlue()) // takes all extra space + contentPane.add(button.peer) + button.peer.setAlignmentX(Component.CENTER_ALIGNMENT) //horizontally centered + contentPane.add(Box.createVerticalStrut(5)) //spacer + // + listenTo(button) + reactions += { + case ButtonClicked(`button`) => + visible = false + dispose() + } + preferredSize = new Dimension(150, 150) + pack() + visible = true + override def closeOperation() = { + close + } +} + +object FrameDemo2 { + //Creates an icon-worthy Image from scratch. + def createFDImage(): Image = { + //Create a 16x16 pixel image. + val bi = new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB) + //Draw into it. + val g: Graphics = bi.getGraphics() + g.setColor(Color.BLACK); + g.fillRect(0, 0, 15, 15) + g.setColor(Color.RED) + g.fillOval(5, 3, 6, 6) + + //Clean up. + g.dispose() + + //Return it. + bi + } + + // Returns an Image or null. + def getFDImage(): Image = { + val imgURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/FD.jpg"); + if (imgURL != null) { + return new ImageIcon(imgURL).getImage(); + } else { + return null; + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Use the Java look and feel. + try { + UIManager.setLookAndFeel( + UIManager.getCrossPlatformLookAndFeelClassName()); + } catch { + case e: Exception => ; + } + + //Make sure we have nice window decorations. + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + + //Instantiate the controlling class. + val frame = new Frame() { + title = "FrameDemo2" + //Create and set up the content pane. + val demo = new FrameDemo2(); + //Add components to it. + val contentPane = peer.getContentPane() + override def closeOperation() = { + sys.exit(0) + } + } + frame.contentPane.add(frame.demo.createOptionControls(frame), + BorderLayout.CENTER) + frame.contentPane.add(frame.demo.createButtonPane(frame), + BorderLayout.PAGE_END) + //Display the window + frame.pack() + frame.visible = true + } + + //Start the demo. + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI(); + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala new file mode 100644 index 00000000..5d0066b1 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.{ Component, Dimension } +import scala.swing.event.Key + +/* + * Tutorial: How to Use HTML in Swing Components + * http://docs.oracle.com/javase/tutorial/uiswing/components/html.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/HtmlDemoProject/src/components/HtmlDemo.java + * + * HtmlDemo.java needs no other files. + */ +class HtmlDemo extends BoxPanel(Orientation.Horizontal) { + val initialText = "\n" + + "Color and font test:\n" + + "

    \n" + + "
  • red\n" + + "
  • blue\n" + + "
  • green\n" + + "
  • small\n" + + "
  • large\n" + + "
  • italic\n" + + "
  • bold\n" + + "
\n" + val htmlTextArea = new TextArea(10, 20) { + text = initialText + } + val scrollPane = new ScrollPane(htmlTextArea) + val changeTheLabel = new Button("Change the label") { + mnemonic = Key.C + // xAlignment = Alignment.Center + peer.setAlignmentX(Component.CENTER_ALIGNMENT) + } + val theLabel = new Label(initialText) { + minimumSize = new Dimension(200, 200) + preferredSize = new Dimension(200, 200) + maximumSize = new Dimension(200, 200) + verticalAlignment = Alignment.Center + horizontalAlignment = Alignment.Center + } + + val leftPanel = new BoxPanel(Orientation.Vertical) { + border = Swing.CompoundBorder( + Swing.TitledBorder(Swing.EmptyBorder, "Edit the HTML, then click the button"), + Swing.EmptyBorder(10, 10, 10, 10)) + contents ++= Array( scrollPane, Swing.RigidBox(new Dimension(0, 10)), changeTheLabel ) + } + + val rightPanel = new BoxPanel(Orientation.Vertical) { + border = Swing.CompoundBorder( + Swing.TitledBorder(Swing.EmptyBorder, "A label with HTML"), + Swing.EmptyBorder(10, 10, 10, 10)) + contents += theLabel + } + + border = Swing.EmptyBorder(10, 10, 10, 10) + contents += leftPanel + contents += rightPanel + + listenTo(changeTheLabel) + reactions += { + case ButtonClicked(`changeTheLabel`) => theLabel.text = htmlTextArea.text + } +} + +object HtmlDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "HtmlDemo" + //Create and set up the content pane. + val newContentPane = new HtmlDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + //Turn off metal's use of bold fonts + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala new file mode 100644 index 00000000..a697dfc3 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -0,0 +1,242 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.net.URL +import java.awt.RenderingHints +import java.awt.image.BufferedImage +import javax.swing.{ Icon, ImageIcon, JToolBar, SwingWorker } + +/* + * Tutorial: How to Use Icons + * http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/IconDemoApp.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/MissingIcon.java + * + * IconDemoApp.scala + * MissingIcon.scala + */ +/** + * This application is intended to demonstrate the loading of image files into icons + * for use in a Swing user interface. It creates a toolbar with a thumbnail preview + * of each image. Clicking on the thumbnail will show the full image + * in the main display area. + * + * IconDemoApp.scala requires the following files:
+ * The following files are copyright 2006 spriggs.net and licensed under a + * Creative Commons License (http://creativecommons.org/licenses/by-sa/3.0/) + *
+ * /scala/swing/examples/tutorials/images/sunw01.jpg
+ * /scala/swing/examples/tutorials/images/sunw02.jpg
+ * images/sunw03.jpg
+ * /scala/swing/examples/tutorials/images/sunw04.jpg
+ * /scala/swing/examples/tutorials/images/sunw05.jpg
+ * + * @author Collin Fagan + * @date 7/25/2007 + * @version 2.0 + */ +class IconDemoApp extends Frame { + + private val imagedir = "/scala/swing/examples/tutorials/images/" + private val placeholderIcon = new MissingIcon() + + /** + * List of all the descriptions of the image files. These correspond one to + * one with the image file names + */ + private val imageFileNames = Array[String]("sunw01.jpg", "sunw02.jpg", + "sunw03.jpg", "sunw04.jpg", "sunw05.jpg") + + private val imageCaptions = Array[String]("Original SUNW Logo", "The Clocktower", + "Clocktower from the West", "The Mansion", "Sun Auditorium") + + // A label for displaying the pictures + private val photographLabel = new Label() { + verticalTextPosition = Alignment.Bottom + horizontalTextPosition = Alignment.Center + horizontalAlignment = Alignment.Center + border = Swing.EmptyBorder(5, 5, 5, 5) + } + + // We add two glue components. Later in process() we will add thumbnail buttons + // to the toolbar in between these glue components. This will center the + // buttons in the toolbar. + private val buttonBar = new ToolBar() { + contents += Swing.Glue + contents += Swing.Glue + } + contents = new BorderPanel() { + layout(buttonBar) = BorderPanel.Position.South + layout(photographLabel) = BorderPanel.Position.Center + } + visible = true + size = new Dimension(400, 300) + + // this centers the frame on the screen + // setLocationRelativeTo(null) + + // start the image loading SwingWorker in a background thread + loadImages.execute() + + override def closeOperation() = { + sys.exit(0) + } + + /** + * SwingWorker class that loads the images a background thread and calls publish + * when a new one is ready to be displayed. + * + * We use Unit as the first SwingWroker param as we do not need to return + * anything from doInBackground(). + */ + def loadImages(): SwingWorker[Unit, ThumbnailAction] = + new SwingWorker[Unit, ThumbnailAction]() { + /** + * Creates full size and thumbnail versions of the target image files. + */ + override protected def doInBackground(): Unit = { + println("doInBackground") + for (i <- 0 until imageCaptions.length) { + val icon: ImageIcon = IconDemoApp.createImageIcon(imagedir + imageFileNames(i), imageCaptions(i)).get + + val thumbAction: ThumbnailAction = + if (icon != null) { + val thumbnailIcon: ImageIcon = new ImageIcon(getScaledImage(icon.getImage(), 32, 32)) + new ThumbnailAction(icon, thumbnailIcon, imageCaptions(i)) + } else { + // the image failed to load for some reason + // so load a placeholder instead + new ThumbnailAction(placeholderIcon, placeholderIcon, imageCaptions(i)) + } + publish(thumbAction); + } + } + + /** + * Process all loaded images. + */ + override def process(chunks: java.util.List[ThumbnailAction]): Unit = { + println("process") + // Problem: process never gets called. + val it: java.util.Iterator[ThumbnailAction] = chunks.iterator() + while (it.hasNext()) { + val thumbAction = it.next() + val thumbButton = new Button(thumbAction); + // add the new button BEFORE the last glue + // this centers the buttons in the toolbar + buttonBar.contents.dropRight(1) + buttonBar.contents += new Button(thumbAction) + buttonBar.contents += Swing.Glue + } + } + + /** + * Done. + */ + override def done(): Unit = { + println("Done") + } + } + + /** + * Resizes an image using a Graphics2D object backed by a BufferedImage. + * @param srcImg - source image to scale + * @param w - desired width + * @param h - desired height + * @return - the new resized image + */ + private def getScaledImage(srcImg: Image, w: Int, h: Int): Image = { + val resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) + val g2: Graphics2D = resizedImg.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(srcImg, 0, 0, w, h, null); + g2.dispose(); + resizedImg; + } +} + +object IconDemoApp { + def createImageIcon(path: String, + description: String): Option[ImageIcon] = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Some(new ImageIcon(imgURL, description)) + } else { + System.err.println("Couldn't find file: " + path); + None + } + } + /** + * Main entry point to the demo. Loads the Swing elements on the "Event + * Dispatch Thread". + * + * @param args + */ + def main(args: Array[String]) { + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run() { + val app = new IconDemoApp() { + visible = true + } + } + }); + } +} + +/** + * @param Icon - The full size photo to show in the button. + * @param Icon - The thumbnail to show in the button. + * @param String - The description of the icon. + */ +class ThumbnailAction(photo: Icon, thumb: Icon, desc: String) extends Action(desc) { + /** + * The icon if the full image we want to display. + */ + private val displayPhoto: Icon = photo + + // The LARGE_ICON_KEY is the key for setting the + // icon when an Action is applied to a butt + peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, desc) + + // The short description becomes the tooltip of a button. + peer.putValue(javax.swing.Action.LARGE_ICON_KEY, thumb) + + def apply() {} +} + + +class ToolBar extends scala.swing.Component with SequentialContainer.Wrapper { + override lazy val peer: JToolBar = new JToolBar with SuperMixin +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IntegerEditor.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IntegerEditor.scala new file mode 100644 index 00000000..d6859044 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IntegerEditor.scala @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *   - Redistributions of source code must retain the above copyright + *     notice, this list of conditions and the following disclaimer. + * + *   - Redistributions in binary form must reproduce the above copyright + *     notice, this list of conditions and the following disclaimer in the + *     documentation and/or other materials provided with the distribution. + * + *   - Neither the name of Oracle or the names of its + *     contributors may be used to endorse or promote products derived + *     from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import javax.swing.AbstractAction +import javax.swing.DefaultCellEditor +import javax.swing.JFormattedTextField +import javax.swing.JOptionPane +import javax.swing.JTable +import javax.swing.KeyStroke +import javax.swing.SwingConstants +import javax.swing.SwingUtilities +import java.awt.event.ActionEvent +import java.awt.event.KeyEvent +import java.awt.Component +import java.awt.Toolkit +import java.text.NumberFormat +import java.text.ParseException +import javax.swing.text.DefaultFormatterFactory +import javax.swing.text.NumberFormatter + +@SerialVersionUID(1L) +class IntegerEditor(min: Int, max: Int) extends DefaultCellEditor(new JFormattedTextField()) { + + var ftf: JFormattedTextField = getComponent.asInstanceOf[JFormattedTextField] + + var integerFormat: NumberFormat = NumberFormat.getIntegerInstance + + private var minimum: java.lang.Integer = new java.lang.Integer(min) + + private var maximum: java.lang.Integer = new java.lang.Integer(max) + + private var DEBUG: Boolean = false + + val intFormatter = new NumberFormatter(integerFormat) + + intFormatter.setFormat(integerFormat) + + intFormatter.setMinimum(minimum) + + intFormatter.setMaximum(maximum) + + ftf.setFormatterFactory(new DefaultFormatterFactory(intFormatter)) + + ftf.setValue(minimum) + + ftf.setHorizontalAlignment(SwingConstants.TRAILING) + + ftf.setFocusLostBehavior(JFormattedTextField.PERSIST) + + ftf.getInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check") + + ftf.getActionMap.put("check", new AbstractAction() { + + def actionPerformed(e: ActionEvent) { + if (!ftf.isEditValid) { + if (userSaysRevert()) { + ftf.postActionEvent() + } + } else try { + ftf.commitEdit() + ftf.postActionEvent() + } catch { + case exc: java.text.ParseException => + } + } + }) + + override def getTableCellEditorComponent(table: JTable, value: AnyRef, isSelected: Boolean, row: Int, column: Int): Component = { + val ftf = super.getTableCellEditorComponent(table, value, isSelected, row, column).asInstanceOf[JFormattedTextField] + ftf.setValue(value) + ftf + } + + override def getCellEditorValue(): AnyRef = { + val ftf = getComponent.asInstanceOf[JFormattedTextField] + val o = ftf.getValue + if (o.isInstanceOf[java.lang.Integer]) { + o + } else if (o.isInstanceOf[Number]) { + new java.lang.Integer(o.asInstanceOf[Number].intValue()) + } else { + if (DEBUG) { + println("getCellEditorValue: o isn't a Number") + } + try { + integerFormat.parseObject(o.toString) + } catch { + case exc: ParseException => { + System.err.println("getCellEditorValue: can't parse o: " + o) + null + } + } + } + } + + override def stopCellEditing(): Boolean = { + val ftf = getComponent.asInstanceOf[JFormattedTextField] + if (ftf.isEditValid) { + try { + ftf.commitEdit() + } catch { + case exc: java.text.ParseException => + } + } else { + if (!userSaysRevert()) { + return false + } + } + super.stopCellEditing() + } + + protected def userSaysRevert(): Boolean = { + Toolkit.getDefaultToolkit.beep() + ftf.selectAll() + val options = Array[Object]("Edit", "Revert") + val answer = JOptionPane.showOptionDialog(SwingUtilities.getWindowAncestor(ftf), + "The value must be an integer between " + minimum + " and " + maximum + ".\n" + + "You can either continue editing " + "or revert to the last valid value.", + "Invalid Text Entered", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, + null, + options, + options(1)) + if (answer == 1) { + ftf.setValue(ftf.getValue) + return true + } + false + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala new file mode 100644 index 00000000..3d4143a4 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import javax.swing.ImageIcon +import java.net.URL +/* + * Tutorial: How to Use Labels + * http://docs.oracle.com/javase/tutorial/uiswing/components/label.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/LabelDemoProject/src/components/LabelDemo.java + * + * LabelDemo.scala needs one other file: + * /scala/swing/examples/tutorials/images/middle.gif + */ +class LabelDemo extends GridPanel(3, 1) { + val icon: ImageIcon = LabelDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif", + "a pretty but meaningless splat") + //Create the first label. + val label1: Label = new Label("Image and Text", icon, Alignment.Center) { + //Set the position of its text, relative to its icon: + verticalTextPosition = Alignment.Bottom + horizontalTextPosition = Alignment.Center + } + + //Create the other labels. + val label2 = new Label("Text-Only Label") + val label3 = new Label("", icon, Alignment.Center) + + //Create tool tips, for the heck of it. + label1.tooltip = "A label containing both image and text" + label2.tooltip = "A label containing only text" + label3.tooltip = "A label containing only an image" + + contents += label1 + contents += label2 + contents += label3 +} + +object LabelDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String, description: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL, description) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "LabelDemo" + //Create and set up the content pane. + val newContentPane = new LabelDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala new file mode 100644 index 00000000..c81f7c48 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala @@ -0,0 +1,197 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ ButtonClicked, EditDone, SelectionChanged, ValueChanged } +import java.awt.Toolkit +/* + * Tutorial: How to Use Lists + * http://docs.oracle.com/javase/tutorial/uiswing/components/list.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDemoProject/src/components/ListDemo.java + * + * ListDemo.scala requires no other files. + */ +class ListDemo extends BorderPanel { + private val hireString = "Hire" + private val fireString = "Fire" + + private val listModel: Array[String] = Array("Jane Doe", "John Smith", "Kathy Green") + + //Create the list and put it in a scroll pane. + private val initiallySelected = 0 + private val listMe: ListView[String] = new ListView[String](listModel) { + selection.intervalMode = ListView.IntervalMode.Single + selectIndices(initiallySelected) + visibleRowCount = 5 + } + + val listScrollPane: ScrollPane = new ScrollPane(listMe) + val hireButton: Button = new Button(hireString) { + enabled = false + // actionCommand = hireString + } + val fireButton: Button = new Button(fireString) { + // actionComand = fireString + } + val employeeName: TextField = new TextField(10) + // employeeName.peer.getDocument().addDocumentListener(hireListener); + val nameSelected: String = listModel(initiallySelected) + + //Create a panel that uses BoxLayout. + val buttonPane = new BoxPanel(Orientation.Horizontal) { + border = Swing.EmptyBorder(5, 5, 5, 5) + contents += fireButton + contents += Swing.HStrut(5) + contents += fireButton + contents += Swing.HStrut(5) + contents += new Separator() + contents += Swing.HStrut(5) + contents += employeeName + contents += hireButton + } + + layout(listScrollPane) = BorderPanel.Position.Center + layout(buttonPane) = BorderPanel.Position.South + + listenTo(listMe.selection) + listenTo(fireButton) + listenTo(employeeName) + listenTo(hireButton) + + reactions += { + case ButtonClicked(`fireButton`) => + fireListenerMethod() + case EditDone(`employeeName`) => + hireListenerMethod() + case ButtonClicked(`hireButton`) => + hireListenerMethod() + case SelectionChanged(`listMe`) => + fireButton.enabled = listMe.selection.leadIndex >= 0 + case ValueChanged(`employeeName`) => + hireButton.enabled = employeeName.text.trim().length > 0 + } + //This method tests for string equality. You could certainly + //get more sophisticated about the algorithm. For example, + //you might want to ignore white space and capitalization. + def alreadyInList(name: String): Boolean = { + listMe.listData.contains(name); + } + def fireListenerMethod(): Unit = { + //This method can be called only if + //there's a valid selection + //so go ahead and remove whatever's selected. + var index: Int = listMe.selection.leadIndex + val (x, y) = listMe.listData.splitAt(index) + listMe.listData = x ++ y.tail + + val size: Int = listMe.listData.size + + if (size == 0) { //Nobody's left, disable firing. + fireButton.enabled = false + } else { //Select an index. + if (index == size) { + //removed item in last position + index -= 1 + } + listMe.selectIndices(index); + listMe.ensureIndexIsVisible(index); + } + } + def hireListenerMethod(): Unit = { + val nameSelected: String = employeeName.text + //User didn't type in a unique name... + if (nameSelected.equals("") || alreadyInList(nameSelected)) { + Toolkit.getDefaultToolkit().beep() + employeeName.requestFocusInWindow() + employeeName.selectAll() + } else { + var index: Int = listMe.selection.leadIndex //get selected index + if (index == -1) { //no selection, so insert at beginning + index = 0 + } else { //add after the selected item + index += 1 + } + + val (x: Seq[String], y: Seq[String]) = listMe.listData.splitAt(index) + val z = employeeName.text +: y + listMe.listData = x ++ z + //If we just wanted to add to the end, we'd do this: + //listModel.listData += employeeName.text; + + //Reset the text field. + employeeName.requestFocusInWindow() + employeeName.text = "" + + //Select the new item and make it visible. + listMe.selectIndices(index) + listMe.ensureIndexIsVisible(index) + } + } +} +object ListDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame: Frame = new Frame() { + title = "ListDemo" + override def closeOperation() = { + sys.exit(0) + } + } + //Create and set up the content pane. + val newContentPane = new ListDemo() { + opaque = true + } + frame.contents = newContentPane + + //Display the window. + frame.pack() + frame.visible = true + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala new file mode 100644 index 00000000..d651cd57 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components +import java.awt.{Dimension, GraphicsConfiguration, Point} +import scala.swing._ +import scala.swing.event.{ButtonClicked, Key, MouseClicked} + +/* + * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java + */ +/** + * Use this modal dialog to let the user choose one string from a long + * list. See ListDialogRunner.scala for an example of using ListDialog. + * The basics: + *
+ * String[] choices = {"A", "long", "array", "of", "strings"};
+ * String selectedName = ListDialog.showDialog(
+ * componentInControllingFrame,
+ * locatorComponent,
+ * "A description of the list:",
+ * "Dialog Title",
+ * choices,
+ * choices[0]);
+ * 
+ */ +class ListDialog(frame: Frame, locationComp: Component, + labelText: String, title: String, data: Array[String], + initialValue: String, longValue: String) extends Dialog( + frame: Window, + frame.peer.getGraphicsConfiguration: GraphicsConfiguration) { + // Must be a modal dialog. Otherwise the showDialog call will return + // immediately and the value returned will not reflect the user's + // selections. + peer.setModal(true) + val cancelButton = new Button("Cancel") + val setButton = new Button("Set") + val list = new ListView[String](data) { + if (longValue != null) { + prototypeCellValue = longValue + visibleRowCount = -1 + } + selection.intervalMode = ListView.IntervalMode.SingleInterval + } + // Setting the selection mode of the peer does not have an effect. + list.peer.setLayoutOrientation(javax.swing.JList.HORIZONTAL_WRAP) + val lSelect = list.selection + defaultButton = setButton + // + val listScroller = new ScrollPane(list) { + preferredSize = new Dimension(250, 80) + peer.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT) + } + // + //Create a container so that we can add a title around + //the scroll pane. Can't add a title directly to the + //scroll pane because its background would be white. + //Lay out the label and scroll pane from top to bottom. + val label = new Label(labelText) + val listPane = new BoxPanel(Orientation.Vertical) { + border = Swing.EmptyBorder(10, 10, 10, 10) + contents += label + contents += Swing.RigidBox(new Dimension(0, 5)) + contents += listScroller + } + + val buttonPane = new BoxPanel(Orientation.Horizontal) { + border = Swing.EmptyBorder(0, 10, 10, 10) + contents += Swing.HGlue + contents += cancelButton + contents += Swing.HGlue + contents += setButton + } + + contents = new BorderPanel { + add(listPane, BorderPanel.Position.Center) + add(buttonPane, BorderPanel.Position.South) + } + + //Initialize values. + setValue(initialValue) + // Events + listenTo(setButton) + listenTo(cancelButton) + listenTo(list.mouse.clicks) +// listenTo(list.selection) + //Getting the selections out of the ListView is problematic. I can't figure out a way to get + //it to work. There are no demos available that use ListViews and actually consume the choices + //made with the list. Maybe it is a broken component? + reactions += { + case ButtonClicked(`setButton`) => + setValue(list.listData(list.selection.leadIndex)) + visible = false + case ButtonClicked(`cancelButton`) => + setValue(initialValue) + visible = false +// case SelectionChanged(`list`) => +// println("SelectionChanged") +// println(list.selection.leadIndex) + case MouseClicked(source: Component, point: Point, modifiers: Key.Modifiers, + clicks: Int, triggersPopup: Boolean) => if (clicks == 2) setButton.doClick + } + // + pack() + setLocationRelativeTo(locationComp) + + private def setValue(newValue: String): Unit = { + ListDialog.value = newValue + } +} + +object ListDialog { + + var value: String = "" + + /** + * Set up and show the dialog. The first Component argument + * determines which frame the dialog depends on; it should be + * a component in the dialog's controlling frame. The second + * Component argument should be null if you want the dialog + * to come up with its left corner in the center of the screen; + * otherwise, it should be the component on top of which the + * dialog should appear. + */ + def showDialog(frameComp: Frame, locationComp: Component, + labelText: String, + title: String, + possibleValues: Array[String], + initialValue: String, + longValue: String): String = { + val dialog = new ListDialog(frameComp, locationComp, + labelText, title, possibleValues, initialValue, longValue) + dialog.visible = true + value + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala new file mode 100644 index 00000000..b4426e99 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import java.awt.Font +import java.awt.GraphicsEnvironment +import scala.swing._ +import scala.swing.event.ButtonClicked + +/* + * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java + */ +object ListDialogRunner { + val names: Array[String] = Array("Arlo", "Cosmo", "Elmo", "Hugo", + "Jethro", "Laszlo", "Milo", "Nemo", + "Otto", "Ringo", "Rocco", "Rollo") + var frame: Frame = null + + def createUI(): BoxPanel = { + val panel = new BoxPanel(Orientation.NoOrientation) { + //Create the labels. + val intro = new Label("The chosen name:") + val nameLabel = new Label(names(1)) { + //Use a wacky font if it exists. If not, this falls + //back to a font we know exists. + font = getAFont() + } + intro.peer.setLabelFor(nameLabel.peer) + + //Create the button. + val button = new Button("Pick a new name...") + + contents += intro + contents += nameLabel + contents += button + + listenTo(button) + reactions += { + case ButtonClicked(`button`) => + nameLabel.text = ListDialog.showDialog( + frame, + button, + "Baby names ending in 0:", + "Name chooser", + names.asInstanceOf[Array[String]], + nameLabel.text, + "Cosmo ") + } + } + panel + } + + def getAFont(): Font = { + //initial strings of desired fonts + val desiredFonts = Array[String]("French Script", "FrenchScript", "Bitstream Vera Sans") + //Search for all installed font families. The first + //call may take a while on some systems with hundreds of + //installed fonts, so if possible execute it in idle time, + //and certainly not in a place that delays painting of + //the UI (for example, when bringing up a menu). + // + //In systems with malformed fonts, this code might cause + //serious problems; use the latest JRE in this case. (You'll + //see the same problems if you use Swing's HTML support or + //anything else that searches for all fonts.) If this call + //causes problems for you under the latest JRE, please let + //us know. + val gEnv: GraphicsEnvironment = + GraphicsEnvironment.getLocalGraphicsEnvironment + val existingFamilyNames: Array[String] = gEnv.getAvailableFontFamilyNames + val chosenFonts: Array[Font] = + for { + desiredFont <- desiredFonts + existingFamilyName <- existingFamilyNames + if existingFamilyName.startsWith(desiredFont) + } yield new Font(existingFamilyName, Font.PLAIN, 30) + if (chosenFonts.length > 0) { + chosenFonts(0) + } else { + new Font("Serif", Font.ITALIC, 36) + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + frame = new Frame() { + title = "Name That Baby" + + //Create and set up the content pane. + val contentPane: BoxPanel = createUI() + contentPane.opaque = true + contents = contentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala new file mode 100644 index 00000000..3d011799 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR + * PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ButtonClicked, Key} +import java.net.URL +import javax.swing.{ ImageIcon, KeyStroke } +import java.awt.event.{ ActionEvent, KeyEvent } + +/* + * Tutorial: How to Use Menus + * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java + * + * MenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. + * + * This class is just like MenuLookDemo, except the menu items + * actually do something, thanks to event listeners. + */ +class MenuDemo extends BorderPanel { + val output = new TextArea(5, 30) + val scrollPane = new ScrollPane(output) + layout(scrollPane) = BorderPanel.Position.Center + + def createMenuBar: MenuBar = { + //Create the menu bar. + val menuBar = new MenuBar() + //Build the fist menu. + val menu = new Menu("A Menu") { + mnemonic = Key.A + } + menu.peer.getAccessibleContext().setAccessibleDescription( + "The only menu in this program that has menu items") + menuBar.menus :+ menu + //a group of JMenuItems + val menuItem1 = new MenuItem(new Action("A text-only menu item") { + def apply() = {} + accelerator = Some(KeyStroke.getKeyStroke( + KeyEvent.VK_1, ActionEvent.ALT_MASK)) + longDescription = "This doesn't really do anything" + }) { + mnemonic = Key.T + } + menu.contents += menuItem1 + // + val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val menuItem2 = new MenuItem("Both text and icon") { + icon = icon + mnemonic = Key.B + } + menu.contents += menuItem2 + // + val menuItem3 = new MenuItem("") { + icon = icon + mnemonic = Key.D + } + //a group of radio button menu items + menu.contents += new Separator(Orientation.Horizontal) + val group = new ButtonGroup() + // + val rbMenuItem1 = new RadioMenuItem("A radio button menu item") { + selected = true + mnemonic = Key.R + } + group.buttons += rbMenuItem1 + menu.contents += rbMenuItem1 + // + val rbMenuItem2 = new RadioMenuItem("Another one") { + mnemonic = Key.O + } + group.buttons += rbMenuItem2 + menu.contents += rbMenuItem2 + //a group of check box menu items + menu.contents += new Separator(Orientation.Horizontal) + val cbMenuItem1 = new CheckMenuItem("A check box menu item") { + mnemonic = Key.C + } + menu.contents += cbMenuItem1 + val cbMenuItem2 = new CheckMenuItem("Another one") { + mnemonic = Key.H + } + // + //a submenu + menu.contents += new Separator(Orientation.Horizontal) + val submenu = new Menu("A submenu") { + mnemonic = Key.S + } + val menuItemS1 = new MenuItem(new Action("An item in the submenu") { + def apply() = {} + accelerator = Some(KeyStroke.getKeyStroke( + KeyEvent.VK_2, ActionEvent.ALT_MASK)) + }) + submenu.contents += menuItemS1 + // + val menuItemS2 = new MenuItem("Another item") + submenu.contents += menuItemS2 + menu.contents += submenu + // + //Build second menu in the menu bar. + val menu2 = new Menu("Another Menu") { + mnemonic = Key.N + } + menu2.peer.getAccessibleContext().setAccessibleDescription( + "This menu does nothing") + menuBar.contents += menu + menuBar.contents += menu2 + // + listenTo(menuItem1) + listenTo(menuItem2) + listenTo(menuItem3) + listenTo(rbMenuItem1) + listenTo(rbMenuItem2) + listenTo(cbMenuItem1) + listenTo(cbMenuItem2) + listenTo(menuItemS1) + reactions += { + case ButtonClicked(`menuItem1`) => actionPerformed(menuItem1) + case ButtonClicked(`menuItem2`) => actionPerformed(menuItem2) + case ButtonClicked(`menuItem3`) => actionPerformed(menuItem3) + case ButtonClicked(`rbMenuItem1`) => actionPerformed(rbMenuItem1) + case ButtonClicked(`rbMenuItem2`) => actionPerformed(rbMenuItem2) + case ButtonClicked(`cbMenuItem1`) => actionPerformed(cbMenuItem1) + case ButtonClicked(`cbMenuItem2`) => actionPerformed(cbMenuItem2) + case ButtonClicked(`menuItemS1`) => actionPerformed(menuItemS1) + case ButtonClicked(`menuItemS2`) => actionPerformed(menuItemS2) + // No ItemEvents in scala.swing.... +// case SelectionChanged(`menuItem1`) => itemStateChanged(menuItem1) +// case SelectionChanged(`menuItem2`) => itemStateChanged(menuItem2) +// case SelectionChanged(`menuItem3`) => itemStateChanged(menuItem3) +// case SelectionChanged(`rbMenuItem1`) => itemStateChanged(rbMenuItem1) +// case SelectionChanged(`rbMenuItem2`) => itemStateChanged(rbMenuItem2) +// case SelectionChanged(`cbMenuItem1`) => itemStateChanged(cbMenuItem1) +// case SelectionChanged(`cbMenuItem2`) => itemStateChanged(cbMenuItem2) +// case SelectionChanged(`menuItemS1`) => itemStateChanged(menuItemS1) +// case SelectionChanged(`menuItemS2`) => itemStateChanged(menuItemS2) + } + menuBar + } + + def actionPerformed(source: MenuItem) { + val newline = "\n" + val s = "Action event detected." + + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")"; + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() + } + + def itemStateChanged(source: MenuItem) { + val newline = "\n" + val s = "Item event detected." + + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")" + + newline + + " New state: " + + (if (source.selected) "selected" else "unselected") + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() + } + + // Returns just the class name -- no package info. + def getClassName(o: AnyRef) { + val classString = o.getClass().getName() + val dotIndex = classString.lastIndexOf(".") + classString.substring(dotIndex + 1) + } +} + +object MenuDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame: Frame = new Frame() { + title = "MenuDemo" + override def closeOperation() = { + sys.exit(0) + } + } + //Create and set up the content pane. + val newContentPane = new MenuDemo() { + opaque = true + } + frame.menuBar = newContentPane.createMenuBar + frame.contents = newContentPane + + //Display the window. + frame.pack() + frame.visible = true + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala new file mode 100644 index 00000000..086ccf19 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala @@ -0,0 +1,102 @@ + +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ + +/* + * Tutorial: How to Use Menus + * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuGlueDemoProject/src/components/MenuGlueDemo.java + * + * MenuGlueDemo.scala requires no other files. + * + * @author ges + * @author kwalrath + */ +/* MenuGlueDemo.scala requires no other files. */ +class MenuGlueDemo { + def createMenuBar(): MenuBar = { + val menuBar = new MenuBar(); + menuBar.contents += createMenu("Menu 1") + menuBar.contents += createMenu("Menu 2") + menuBar.contents += Swing.HGlue + menuBar.contents += createMenu("Menu 3") + menuBar; + } + + def createMenu(title: String): Menu = { + val m = new Menu(title); + m.contents += new MenuItem("Menu item #1 in " + title) + m.contents += new MenuItem("Menu item #2 in " + title) + m.contents += new MenuItem("Menu item #3 in " + title) + m; + } +} + +object MenuGlueDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame = new Frame() { + title = "MenuGlueDemo" + //Create and set up the content pane. + val demo = new MenuGlueDemo(); + // Display the window + contents = new FlowPanel() { + contents += demo.createMenuBar() + } + size = new Dimension(300, 100) + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI(); + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala new file mode 100644 index 00000000..59819d34 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR + * PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.Key +import java.net.URL +import javax.swing.{ ImageIcon, KeyStroke } +import java.awt.event.{ ActionEvent, KeyEvent } + +/* + * Tutorial: How to Use Menus + * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuLookDemoProject/src/components/MenuLookDemo.java + * + * MenuLookDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. + * + * This class exists solely to show you what menus look like. + * It has no menu-related event handling. + */ +class MenuLookDemo extends BorderPanel { + val output = new TextArea(5, 30) + val scrollPane = new ScrollPane(output) + layout(scrollPane) = BorderPanel.Position.Center + + def createMenuBar: MenuBar = { + //Create the menu bar. + val menuBar = new MenuBar() + //Build the fist menu. + val menu = new Menu("A Menu") { + mnemonic = Key.A + } + menu.peer.getAccessibleContext().setAccessibleDescription( + "The only menu in this program that has menu items") + menuBar.menus :+ menu + //a group of JMenuItems + val menuItem1 = new MenuItem(new Action("A text-only menu item") { + def apply() = {} + accelerator = Some(KeyStroke.getKeyStroke( + KeyEvent.VK_1, ActionEvent.ALT_MASK)) + longDescription = "This doesn't really do anything" + }) { + mnemonic = Key.T + } + menu.contents += menuItem1 + // + val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val menuItem2 = new MenuItem("Both text and icon") { + icon = icon + mnemonic = Key.B + } + menu.contents += menuItem2 + // + val menuItem3 = new MenuItem("") { + icon = icon + mnemonic = Key.D + } + //a group of radio button menu items + menu.contents += new Separator(Orientation.Horizontal) + val group = new ButtonGroup() + // + val rbMenuItem1 = new RadioMenuItem("A radio button menu item") { + selected = true + mnemonic = Key.R + } + group.buttons += rbMenuItem1 + menu.contents += rbMenuItem1 + // + val rbMenuItem2 = new RadioMenuItem("Another one") { + mnemonic = Key.O + } + group.buttons += rbMenuItem2 + menu.contents += rbMenuItem2 + //a group of check box menu items + menu.contents += new Separator(Orientation.Horizontal) + val cbMenuItem1 = new CheckMenuItem("A check box menu item") { + mnemonic = Key.C + } + menu.contents += cbMenuItem1 + val cbMenuItem2 = new CheckMenuItem("Another one") { + mnemonic = Key.H + } + // + //a submenu + menu.contents += new Separator(Orientation.Horizontal) + val submenu = new Menu("A submenu") { + mnemonic = Key.S + } + val menuItemS1 = new MenuItem(new Action("An item in the submenu") { + def apply() = {} + accelerator = Some(KeyStroke.getKeyStroke( + KeyEvent.VK_2, ActionEvent.ALT_MASK)) + }) + submenu.contents += menuItemS1 + // + val menuItemS2 = new MenuItem("Another item") + submenu.contents += menuItemS2 + menu.contents += submenu + // + //Build second menu in the menu bar. + val menu2 = new Menu("Another Menu") { + mnemonic = Key.N + } + menu2.peer.getAccessibleContext().setAccessibleDescription( + "This menu does nothing") + menuBar.contents += menu + menuBar.contents += menu2 + menuBar + } + + def actionPerformed(source: MenuItem) { + val newline = "\n" + val s = "Action event detected." + + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")"; + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() + } + + def itemStateChanged(source: MenuItem) { + val newline = "\n" + val s = "Item event detected." + + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")" + + newline + + " New state: " + + (if (source.selected) "selected" else "unselected") + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() + } + + // Returns just the class name -- no package info. + def getClassName(o: AnyRef) { + val classString = o.getClass().getName() + val dotIndex = classString.lastIndexOf(".") + classString.substring(dotIndex + 1) + } +} + +object MenuLookDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame: Frame = new Frame() { + title = "MenuLookDemo" + override def closeOperation() = { + sys.exit(0) + } + } + //Create and set up the content pane. + val newContentPane = new MenuLookDemo() { + opaque = true + } + frame.menuBar = newContentPane.createMenuBar + frame.contents = newContentPane + + //Display the window. + frame.pack() + frame.visible = true + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala new file mode 100644 index 00000000..21c3dc81 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR + * PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import java.awt.BasicStroke +import java.awt.Color +import java.awt.Component +import java.awt.Graphics +import java.awt.Graphics2D +import javax.swing.Icon + +/** + * The "missing icon" is a white box with a black border and a red x. + * It's used to display something when there are issues loading an + * icon from an external location. + * + * @author Collin Fagan + * @date 7/25/2007 + */ +class MissingIcon extends Icon { + + private val width = 32 + private val height = 32 + + private val stroke = new BasicStroke(4) + + def paintIcon(c: Component, g: Graphics, x: Int, y: Int): Unit = { + val g2d: Graphics2D = g.create().asInstanceOf[Graphics2D] + + g2d.setColor(Color.WHITE) + g2d.fillRect(x + 1, y + 1, width - 2, height - 2) + + g2d.setColor(Color.BLACK) + g2d.drawRect(x + 1, y + 1, width - 2, height - 2) + + g2d.setColor(Color.RED) + + g2d.setStroke(stroke) + g2d.drawLine(x + 10, y + 10, x + width - 10, y + height - 10) + g2d.drawLine(x + 10, y + height - 10, x + width - 10, y + 10) + + g2d.dispose() + } + + def getIconWidth(): Int = { + width + } + + def getIconHeight(): Int = { + height + } + +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala new file mode 100644 index 00000000..9aafcc38 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala @@ -0,0 +1,121 @@ +package scala.swing.examples.tutorials.components + +import scala.swing._ + +/* + * Tutorial: How to Use Password Fields + * http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PasswordDemoProject/src/components/PasswordDemo.java + * + * PasswordDemo.scala requires no other files. + */ +class PasswordDemo(val controllingFrame: Frame) extends FlowPanel { + private val OK = "ok" + private val Help = "help" + val passwordField = new PasswordField(10) + val label = new Label("Enter the password: ") + label.peer.setLabelFor(passwordField.peer) + + val buttonPane = createButtonPanel() + val textPane = new FlowPanel() + textPane.contents += label + textPane.contents += passwordField + // + contents += textPane + contents += buttonPane + + def createButtonPanel(): GridPanel = { + val p = new GridPanel(0, 1) + val okButton = new Button(Action("OK") { + val input: Array[Char] = passwordField.password + if (PasswordDemo.isPasswordCorrect(input)) { + Dialog.showMessage(p, + "Success! You typed the right password.", + "Passord Success", Dialog.Message.Info, Swing.EmptyIcon) + } else { + Dialog.showMessage(p, + "Invalid password. Try again.", + "Error Message", + Dialog.Message.Error, Swing.EmptyIcon) + } + //Zero out the possible password, for security. + for (i <- 0 until input.length) { + input(i) = '0' + } + passwordField.selectAll() + passwordField.requestFocusInWindow() + }) + val helpButton = new Button(Action("Help") { + Dialog.showMessage(p, + "You can get the password by searching this example's\n" + + "source code for the string \"correctPassword\".\n" + + "Or look at the section How to Use Password Fields in\n" + + "the components section of The Java Tutorial.", + "Passord Help", Dialog.Message.Info, Swing.EmptyIcon) + }) + p.contents += okButton + p.contents += helpButton + listenTo(okButton) + listenTo(helpButton) + p + } +} + +object PasswordDemo { + /** + * Checks the passed-in array against the correct password. + * After this method returns, you should invoke eraseArray + * on the passed-in array. + */ + def isPasswordCorrect(input: Array[Char]): Boolean = { + val correctPassword = Array[Char]('b', 'u', 'g', 'a', 'b', 'o', 'o') + + val isCorrect = if (input.length != correctPassword.length) { + false; + } else { + var same = true + for (i <- 0 until input.length) { + same &= input(i) == correctPassword(i) + } + same + } + + //Zero out the password. + // Arrays.fill(correctPassword,'0'); + for (i <- 0 until correctPassword.length) + correctPassword.update(i, '0') + isCorrect; + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event dispatch thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "PasswordDemo" + //Create and set up the content pane. + val newContentPane = new PasswordDemo(this) + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + //The standard main method. + def main(args: Array[String]): Unit = { + //Schedule a job for the event dispatch thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }); + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala new file mode 100644 index 00000000..bd6cf81b --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -0,0 +1,284 @@ + +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ButtonClicked, Key, MousePressed, MouseReleased} +import java.net.URL +import javax.swing.{ ImageIcon, KeyStroke } +import java.awt.event.{ ActionEvent, KeyEvent } +import java.awt.Point + +/* + * Tutorial: How to Use Password Fields + * http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PopupMenuDemoProject/src/components/PopupMenuDemo.java + * + * PopupMenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. + * + * Like MenuDemo, but with popup menus added. + */ +class PopupMenuDemo extends BorderPanel { + val output = new TextArea(5, 30) + val scrollPane = new ScrollPane(output) + layout(scrollPane) = BorderPanel.Position.Center + + listenTo(output.mouse.clicks) + + def createMenuBar: MenuBar = { + //Create the menu bar. + val menuBar = new MenuBar() + //Build the fist menu. + val menu = new Menu("A Menu") { + mnemonic = Key.A + } + menu.peer.getAccessibleContext().setAccessibleDescription( + "The only menu in this program that has menu items") + menuBar.menus :+ menu + //a group of JMenuItems + val menuItem1 = new MenuItem(new Action("A text-only menu item") { + def apply() = {} + accelerator = Some(KeyStroke.getKeyStroke( + KeyEvent.VK_1, ActionEvent.ALT_MASK)) + longDescription = "This doesn't really do anything" + }) { + mnemonic = Key.T + } + menu.contents += menuItem1 + // + val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val menuItem2 = new MenuItem("Both text and icon") { + icon = icon + mnemonic = Key.B + } + menu.contents += menuItem2 + // + val menuItem3 = new MenuItem("") { + icon = icon + mnemonic = Key.D + } + //a group of radio button menu items + menu.contents += new Separator(Orientation.Horizontal) + val group = new ButtonGroup() + // + val rbMenuItem1 = new RadioMenuItem("A radio button menu item") { + selected = true + mnemonic = Key.R + } + group.buttons += rbMenuItem1 + menu.contents += rbMenuItem1 + // + val rbMenuItem2 = new RadioMenuItem("Another one") { + mnemonic = Key.O + } + group.buttons += rbMenuItem2 + menu.contents += rbMenuItem2 + //a group of check box menu items + menu.contents += new Separator(Orientation.Horizontal) + val cbMenuItem1 = new CheckMenuItem("A check box menu item") { + mnemonic = Key.C + } + menu.contents += cbMenuItem1 + val cbMenuItem2 = new CheckMenuItem("Another one") { + mnemonic = Key.H + } + // + //a submenu + menu.contents += new Separator(Orientation.Horizontal) + val submenu = new Menu("A submenu") { + mnemonic = Key.S + } + val menuItemS1 = new MenuItem(new Action("An item in the submenu") { + def apply() = {} + accelerator = Some(KeyStroke.getKeyStroke( + KeyEvent.VK_2, ActionEvent.ALT_MASK)) + }) + submenu.contents += menuItemS1 + // + val menuItemS2 = new MenuItem("Another item") + submenu.contents += menuItemS2 + menu.contents += submenu + // + //Build second menu in the menu bar. + val menu2 = new Menu("Another Menu") { + mnemonic = Key.N + } + menu2.peer.getAccessibleContext().setAccessibleDescription( + "This menu does nothing") + menuBar.contents += menu + menuBar.contents += menu2 + // + listenTo(menuItem1) + listenTo(menuItem2) + listenTo(menuItem3) + listenTo(rbMenuItem1) + listenTo(rbMenuItem2) + listenTo(cbMenuItem1) + listenTo(cbMenuItem2) + listenTo(menuItemS1) + reactions += { + case ButtonClicked(`menuItem1`) => actionPerformed(menuItem1) + case ButtonClicked(`menuItem2`) => actionPerformed(menuItem2) + case ButtonClicked(`menuItem3`) => actionPerformed(menuItem3) + case ButtonClicked(`rbMenuItem1`) => actionPerformed(rbMenuItem1) + case ButtonClicked(`rbMenuItem2`) => actionPerformed(rbMenuItem2) + case ButtonClicked(`cbMenuItem1`) => actionPerformed(cbMenuItem1) + case ButtonClicked(`cbMenuItem2`) => actionPerformed(cbMenuItem2) + case ButtonClicked(`menuItemS1`) => actionPerformed(menuItemS1) + case ButtonClicked(`menuItemS2`) => actionPerformed(menuItemS2) + // No ItemEvents in scala.swing.... + // case SelectionChanged(`menuItem1`) => itemStateChanged(menuItem1) + // case SelectionChanged(`menuItem2`) => itemStateChanged(menuItem2) + // case SelectionChanged(`menuItem3`) => itemStateChanged(menuItem3) + // case SelectionChanged(`rbMenuItem1`) => itemStateChanged(rbMenuItem1) + // case SelectionChanged(`rbMenuItem2`) => itemStateChanged(rbMenuItem2) + // case SelectionChanged(`cbMenuItem1`) => itemStateChanged(cbMenuItem1) + // case SelectionChanged(`cbMenuItem2`) => itemStateChanged(cbMenuItem2) + // case SelectionChanged(`menuItemS1`) => itemStateChanged(menuItemS1) + // case SelectionChanged(`menuItemS2`) => itemStateChanged(menuItemS2) + } + menuBar + } + + def actionPerformed(source: MenuItem) { + val newline = "\n" + val s = "Action event detected." + + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")"; + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() + } + + def itemStateChanged(source: MenuItem) { + val newline = "\n" + val s = "Item event detected." + + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")" + + newline + + " New state: " + + (if (source.selected) "selected" else "unselected") + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() + } + + // Returns just the class name -- no package info. + def getClassName(o: AnyRef) { + val classString = o.getClass().getName() + val dotIndex = classString.lastIndexOf(".") + classString.substring(dotIndex + 1) + } + + def createPopupMenu(): Unit = { + //Create the popup menu. + val menuItem1P = new MenuItem("A popup menu item") + val menuItem2P = new MenuItem("Another popup menu item") + val popup = new PopupMenu() { + contents += menuItem1P + contents += menuItem2P + } + //Add listener to the text area so the popup menu can come up. + // MouseListener popupListener = new PopupListener(popup); + // output.addMouseListener(popupListener); + + listenTo(menuItem1P) + listenTo(menuItem2P) + reactions += { + case ButtonClicked(`menuItem1P`) => actionPerformed(menuItem1P) + case ButtonClicked(`menuItem2P`) => actionPerformed(menuItem2P) + // No ItemEvents in scala.swing.... + // case SelectionChanged(`menuItem1P`) => itemStateChanged(menuItem1P) + // case SelectionChanged(`menuItem2P`) => itemStateChanged(menuItem2P) + case MousePressed(source: Component, point: Point, modifiers: Key.Modifiers, + clicks: Int, triggersPopup: Boolean) => maybeShowPopup(popup, source, point, triggersPopup) + case MouseReleased(source: Component, point: Point, modifiers: Key.Modifiers, + clicks: Int, triggersPopup: Boolean) => maybeShowPopup(popup, source, point, triggersPopup) + } + } + + def maybeShowPopup(popup: PopupMenu, c: Component, p: Point, isPopupTrigger: Boolean): Unit = { + if (isPopupTrigger) { + popup.show(c, p.getX().toInt, p.getY().toInt) + } + } +} + +object PopupMenuDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame: Frame = new Frame() { + title = "PopupMenuDemo" + override def closeOperation() = { + sys.exit(0) + } + } + //Create and set up the content pane. + val demo = new PopupMenuDemo() { + opaque = true + } + frame.menuBar = demo.createMenuBar + frame.contents = demo + //Create and set up the popup menu. + demo.createPopupMenu() + + //Display the window. + frame.size = new Dimension(450, 260) + frame.visible = true + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala new file mode 100644 index 00000000..abd73006 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import java.awt.Dimension +import scala.swing._ +import scala.swing.event.{ ButtonClicked, Key } +import javax.swing.ImageIcon +import java.net.URL + +/* + * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/RadioButtonDemoProject/src/components/RadioButtonDemo.java + * + * RadioButtonDemo.scala requires these files: + * /scala/swing/examples/tutorials/images/Bird.gif + * /scala/swing/examples/tutorials/images/Cat.gif + * /scala/swing/examples/tutorials/images/Dog.gif + * /scala/swing/examples/tutorials/images/Rabbit.gif + * /scala/swing/examples/tutorials/images/Pig.gif + */ +class RadioButtonDemo extends BorderPanel { + + //Create the radio buttons. + val birdButton = new RadioButton(RadioButtonDemo.birdString) { + mnemonic = Key.B + selected = true + } + val catButton = new RadioButton(RadioButtonDemo.catString) { + mnemonic = Key.C + selected = false + } + val dogButton = new RadioButton(RadioButtonDemo.dogString) { + mnemonic = Key.D + selected = false + } + val rabbitButton = new RadioButton(RadioButtonDemo.rabbitString) { + mnemonic = Key.R + selected = false + } + val pigButton = new RadioButton(RadioButtonDemo.pigString) { + mnemonic = Key.P + selected = false + } + + //Group the radio buttons. + val group = new ButtonGroup() { + buttons ++= Seq(birdButton, catButton, dogButton, rabbitButton, pigButton) + } + + //Set up the picture label. + val imgIcon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + + RadioButtonDemo.birdString + + ".gif") + val picture = new Label() { + icon = imgIcon + //The preferred size is hard-coded to be the width of the + //widest image and the height of the tallest image. + //A real program would compute this. + preferredSize = new Dimension(177, 122) + } + + //Put the radio buttons in a column in a panel. + val radioPanel = new GridPanel(0, 1) { + contents ++= Seq(birdButton, catButton, dogButton, rabbitButton, pigButton) + } + + layout(radioPanel) = BorderPanel.Position.East + layout(picture) = BorderPanel.Position.Center + border = Swing.EmptyBorder(20, 20, 20, 20) + + listenTo(birdButton) + listenTo(catButton) + listenTo(dogButton) + listenTo(rabbitButton) + listenTo(pigButton) + + reactions += { + case ButtonClicked(`birdButton`) => + picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.birdString + ".gif") + case ButtonClicked(`catButton`) => + picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.catString + ".gif") + case ButtonClicked(`dogButton`) => + picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.dogString + ".gif") + case ButtonClicked(`rabbitButton`) => + picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.rabbitString + ".gif") + case ButtonClicked(`pigButton`) => + picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.pigString + ".gif") + } +} + +object RadioButtonDemo { + val birdString = "Bird" + val catString = "Cat" + val dogString = "Dog" + val rabbitString = "Rabbit" + val pigString = "Pig" + + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Swing.Icon(imgURL) + } else { + null + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "RadioButtonDemo" + //Create and set up the content pane. + val newContentPane = new RadioButtonDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala new file mode 100644 index 00000000..4a8d1e80 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.awt.{ Color, Font, Graphics, Toolkit } + +class Rule(val orientation: Int, var isMetric: Boolean) extends Component { + val Inch: Int = Toolkit.getDefaultToolkit().getScreenResolution() + val Size = 35 + var units = if (isMetric) { + // dots per centimeter + (Inch.toDouble / 2.54).toInt + } else { + Inch + } + var increment = if (isMetric) { units } else { units / 2 } + def setIsMetric(isMetricArg: Boolean): Unit = { + isMetric = isMetricArg + setIncrementAndUnits() + repaint() + } + def setIncrementAndUnits() { + if (isMetric) { + units = (Inch.toDouble / 2.54).toInt + increment = units + } + else { + units = Inch + increment = units / 2 + } + } + def setPreferredHeight(ph: Int): Unit = { + preferredSize = new Dimension(Size, ph) + } + def setPreferredWidth(pw: Int): Unit = { + preferredSize = new Dimension(pw, Size) + } + def paintComponent(g: Graphics): Unit = { + val drawHere: Rectangle = g.getClipBounds() + + // Fill clipping area with dirty brown/orange. + g.setColor(new Color(230, 163, 4)) + g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height) + + // Do the ruler labels in a small font that's black. + g.setFont(new Font("SansSerif", Font.PLAIN, 10)) + g.setColor(Color.black) + + // Some vars we need. + var end = 0 + var start = 0 + var tickLength = 0 + var text: String = null + + // Use clipping bounds to calculate first and last tick locations. + if (orientation == Rule.Horizontal) { + start = (drawHere.x / increment) * increment; + end = (((drawHere.x + drawHere.width) / increment) + 1) * increment + } else { + start = (drawHere.y / increment) * increment; + end = (((drawHere.y + drawHere.height) / increment) + 1) * increment + } + + // Make a special case of 0 to display the number + // within the rule and draw a units label. + if (start == 0) { + val u = if (isMetric) " cm" else " in" + text = Integer.toString(0) + u + tickLength = 10 + if (orientation == Rule.Horizontal) { + g.drawLine(0, Size - 1, 0, Size - tickLength - 1) + g.drawString(text, 2, 21) + } else { + g.drawLine(Size - 1, 0, Size - tickLength - 1, 0) + g.drawString(text, 9, 10) + } + text = null + start = increment + } + + // ticks and labels + for (i <- start until end by increment) { + if (i % units == 0) { + tickLength = 10 + text = Integer.toString(i / units) + } else { + tickLength = 7 + text = null + } + + if (tickLength != 0) { + if (orientation == Rule.Horizontal) { + g.drawLine(i, Size - 1, i, Size - tickLength - 1) + if (text != null) + g.drawString(text, i - 3, 21) + } else { + g.drawLine(Size - 1, i, Size - tickLength - 1, i) + if (text != null) + g.drawString(text, 9, i + 3) + } + } + } + } +} + +object Rule { + val Horizontal = 0 + val Vertical = 1 +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala new file mode 100644 index 00000000..2ba84fc2 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -0,0 +1,163 @@ + +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import javax.swing.{ImageIcon, ScrollPaneConstants} +import java.awt.{ Color, Dimension, Font } +import java.net.URL +import scala.swing.event.ButtonClicked + +/* + * Tutorial: How to Use Scroll Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Rule.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Corner.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollablePicture.java + * + * ScrollDemo.scala requires these files: + * Rule.scala + * Corner.scala + * ScrollablePicture.scala + * /scala/swing/examples/tutorials/images/flyingBee.jpg + */ +class ScrollDemo extends BoxPanel(Orientation.Horizontal) { + //Get the image to use. + val bee: ImageIcon = ScrollDemo.createImageIcon("/scala/swing/examples/tutorials/images/flyingBee.jpg") + + //Create the row and column headers. + val columnView = new Rule(Rule.Horizontal, true); + val rowView = new Rule(Rule.Vertical, true); + if (bee != null) { + columnView.setPreferredWidth(bee.getIconWidth()) + rowView.setPreferredHeight(bee.getIconHeight()) + } else { + columnView.setPreferredWidth(320) + rowView.setPreferredHeight(480) + } + + //Create the corners. + val isMetric = new ToggleButton("cm") { + selected = true + font = new Font("SansSerif", Font.PLAIN, 11) + margin = new Insets(2, 2, 2, 2) + } + val buttonCorner = new FlowPanel() { + contents += isMetric + } + + //Set up the scroll pane. + val picture = new ScrollablePicture(bee, columnView.increment) + val pictureScrollPane = new ScrollPane(picture) { + preferredSize = new Dimension(300, 250) + columnHeaderView = columnView + rowHeaderView = rowView + } + pictureScrollPane.peer.setViewportBorder(Swing.LineBorder(Color.black)) + + //Set the corners. + //In theory, to support internationalization you would change + //UPPER_LEFT_CORNER to UPPER_LEADING_CORNER, + //LOWER_LEFT_CORNER to LOWER_LEADING_CORNER, and + //UPPER_RIGHT_CORNER to UPPER_TRAILING_CORNER. In practice, + //bug #4467063 makes that impossible (in 1.4, at least). + pictureScrollPane.peer.setCorner(ScrollPaneConstants.UPPER_LEADING_CORNER, buttonCorner.peer) + pictureScrollPane.peer.setCorner(ScrollPaneConstants.LOWER_LEADING_CORNER, new Corner()) + pictureScrollPane.peer.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, new Corner()) + + contents += pictureScrollPane + border = Swing.EmptyBorder(20, 20, 20, 20) + + listenTo(isMetric) + // Original had an itemListener. Scala Swing makes no provision + // for item changed events, so use button clicked instead. + reactions += { + case ButtonClicked(`isMetric`) => if (isMetric.selected) { + // Turn it to metric.. + rowView.setIsMetric(true) + columnView.setIsMetric(true) + } else { + // Turn it to inches. + rowView.setIsMetric(false) + columnView.setIsMetric(false) + } + picture.setMaxUnitIncrement(rowView.increment) + } +} + +object ScrollDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ScrollDemo" + //Create and set up the content pane. + val newContentPane = new ScrollDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala new file mode 100644 index 00000000..fb348421 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala @@ -0,0 +1,166 @@ + +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.MouseReleased +import javax.swing.SwingUtilities +import java.awt.{Color, Dimension, Graphics2D, Rectangle} + +/* + * Tutorial: How to Use Scroll Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemo2Project/src/components/ScrollDemo2.java + * + * ScrollDemo2.scala requires no other files. + */ +class ScrollDemo2 extends BorderPanel { + val colors: Array[Color] = Array( + Color.red, Color.blue, Color.green, Color.orange, + Color.cyan, Color.magenta, Color.darkGray, Color.yellow) + var circles = Seq[Rectangle]() + + //Set up the instructions + val instructionsLeft = new Label("Click left mouse button to place a circle.") + val instructionsRight = new Label("Click right mouse button to clear drawing area.") + val instructionPanel = new GridPanel(0, 1) { + focusable = true + contents += instructionsLeft + contents += instructionsRight + } + + //Set up the drawing area. + val drawingPane = new DrawingPane() { + background = Color.white + } + + //Put the drawing area in a scroll pane. + val scroller = new ScrollPane(drawingPane) { + preferredSize = new Dimension(200, 200) + } + layout(instructionPanel) = BorderPanel.Position.North + layout(scroller) = BorderPanel.Position.Center + + /** The component inside the scroll pane. */ + class DrawingPane extends Panel { +// background = Color.white Definitely not. + preferredSize = new Dimension(200, 200) + focusable = true + val area = new Dimension() + override def paintComponent(g: Graphics2D): Unit = { + super.paintComponent(g); + for (i <- 0 until circles.length) { + val rect: Rectangle = circles(i) + g.setColor(colors((i % colors.length))) + g.fillOval(rect.x, rect.y, rect.width, rect.height); + } + } + listenTo(mouse.clicks) + listenTo(mouse.moves) + listenTo(keys) + reactions += { + case e: MouseReleased => + circles = Seq[Rectangle]() + val W = 100 + val H = 100 + var changed = false + if (SwingUtilities.isRightMouseButton(e.peer)) { + //This will clear the graphic objects. + circles = Seq[Rectangle]() + area.width = 0; + area.height = 0; + changed = true; + } else { + val x = if (e.point.x >= W / 2) e.point.x - W / 2 else 0 + val y = if (e.point.y >= H / 2) e.point.y - H / 2 else 0 + val rect = new Rectangle(x, y, W, H) + circles = circles :+ rect + drawingPane.peer.scrollRectToVisible(rect) + changed = x + W + 2 > area.width + if (changed) { + area.width = x + W + 2 + } + if (y + H + 2 > area.height) { + area.width = y + H + 2 + changed = true + } + if (changed) { + //Update client's preferred size because + //the area taken up by the graphics has + //gotten larger or smaller (if cleared). + preferredSize = area + + //Let the scroll pane know to update itself + //and its scrollbars. + revalidate(); + } + } + repaint() + } + } + +} + +object ScrollDemo2 { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ScrollDemo2" + //Create and set up the content pane. + val newContentPane = new ScrollDemo2(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala new file mode 100644 index 00000000..39a54625 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ Key, MouseDragged, MouseMoved } +import javax.swing.{ ImageIcon, Scrollable, SwingConstants } +import java.awt.{ Color, Dimension, Rectangle } +import scala.swing.event.MouseMoved + +class ScrollablePicture(i: ImageIcon, var maxUnitIncrement: Int) + extends Label("", i, Alignment.Center) with Scrollable { + private var missingPicture = false + if (i == null) { + missingPicture = true + text = "No picture found." + horizontalAlignment = Alignment.Center + opaque = true + background = Color.white + } + + //Let the user scroll by dragging to outside the window. + peer.setAutoscrolls(true) + listenTo(mouse.moves) + reactions += { + case MouseMoved(source: Component, point: Point, modifiers: Key.Modifiers) => + peer.scrollRectToVisible(new Rectangle(point.x, point.y)) + case MouseDragged(source: Component, point: Point, modifiers: Key.Modifiers) => + peer.scrollRectToVisible(new Rectangle(point.x, point.y)) + } + + def getPreferredScrollableViewportSize(): Dimension = { + if (missingPicture) { + new Dimension(320, 480) + } else { + preferredSize + } + } + + def getScrollableUnitIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { + //Get the current position. + val currentPosition = if (orientation == SwingConstants.HORIZONTAL) { + visibleRect.x; + } else { + visibleRect.y; + } + + //Return the number of pixels between currentPosition + //and the nearest tick mark in the indicated direction. + if (direction < 0) { + val newPosition = currentPosition - + (currentPosition / maxUnitIncrement) * maxUnitIncrement + if (newPosition == 0) maxUnitIncrement else newPosition + } else { + ((currentPosition / maxUnitIncrement) + 1) * maxUnitIncrement + -currentPosition + } + } + + def getScrollableBlockIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { + if (orientation == SwingConstants.HORIZONTAL) + visibleRect.width - maxUnitIncrement + else + visibleRect.height - maxUnitIncrement + } + + def getScrollableTracksViewportWidth(): Boolean = { + false + } + + def getScrollableTracksViewportHeight(): Boolean = { + false + } + + def setMaxUnitIncrement(pixels: Int): Unit = { + maxUnitIncrement = pixels + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala new file mode 100644 index 00000000..8ba4c41b --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.MouseClicked +import scala.swing.event.MouseClicked +/* + * Tutorial: How to Use Tables + * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java + * + * SimpleTableDemo.scala requires no other files. + */ +class SimpleTableDemo extends GridPanel(1, 0) { + private val Debug = false + val columnNames: Array[String] = Array("First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) + data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) + data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) + data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) + data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) + data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + + val table = new Table(data, columnNames) { + preferredViewportSize = new Dimension(500, 70) + } + table.peer.setFillsViewportHeight(true) + if (Debug) { + listenTo(table) + reactions += { + case e: MouseClicked => printDebugData(table) + } + } + + //Create the scroll pane and add the table to it. + val scrollPane = new ScrollPane(table) + + //Add the scroll pane to this panel. + contents += scrollPane + + private def printDebugData(table: Table): Unit = { + val numRows = table.rowCount + val numCols = table.peer.getColumnCount() + val model: javax.swing.table.TableModel = table.model + + println("Value of data: ") + for (i <- 0 until numRows) { + System.out.print(" row " + i + ":") + for (j <- 0 until numCols) { + print(" " + model.getValueAt(i, j)) + } + println() + } + println("--------------------------") + } +} + +object SimpleTableDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "SimpleTableDemo" + //Create and set up the content pane. + val newContentPane = new SimpleTableDemo() + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala new file mode 100644 index 00000000..6e1a1004 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + + +import scala.swing._ +import scala.collection.immutable.Range +import scala.swing.event.{ MouseClicked, TableColumnsSelected, TableRowsSelected } +/* + * Tutorial: How to Use Tables + * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableSelectionDemoProject/src/components/SimpleTableSelectionDemo.java + * + * SimpleTableSelectionDemo.scala requires no other files. + */ +class SimpleTableSelectionDemo extends GridPanel(1, 0) { + private val Debug = true + private val AllowColumnSelection = false + private val AllowRowSelection = true + val columnNames: Array[String] = Array("First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) + data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) + data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) + data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) + data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) + data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + + val table = new Table(data, columnNames) { + preferredViewportSize = new Dimension(500, 70) + selection.intervalMode = Table.IntervalMode.Single + } + table.peer.setFillsViewportHeight(true) + + if (AllowRowSelection) { + listenTo(table.selection) + reactions += { + case TableRowsSelected(`table`, range: Range, adjusting: Boolean) => + //Ignore extra messages. + if (!adjusting) { + if (range.isEmpty) { + println("No rows are selected.") + } else { + val selectedRow = range.head + println("Row " + selectedRow + " is now selected.") + } + } + } + } else { + if (table.selection.elementMode == Table.ElementMode.Cell) { + table.selection.elementMode = Table.ElementMode.Column + } else if (table.selection.elementMode == Table.ElementMode.Row) { + table.selection.elementMode = Table.ElementMode.None + } + } + + if (AllowColumnSelection) { // false by default + if (AllowRowSelection || + table.selection.elementMode == Table.ElementMode.Row) { + //We allow both row and column selection, which + //implies that we *really* want to allow individual + //cell selection. + table.selection.elementMode = Table.ElementMode.Cell + } + else if (table.selection.elementMode == Table.ElementMode.None) { + table.selection.elementMode = Table.ElementMode.Column + } + listenTo(table.selection) + reactions += { + case TableColumnsSelected(`table`, range: Range, adjusting: Boolean) => + //Ignore extra messages. + if (!adjusting) { + if (range.isEmpty) { + println("No rows are selected.") + } else { + val selectedColumn = range.head + println("Column " + selectedColumn + " is now selected.") + } + } + } + } + if (Debug) { + listenTo(table) + reactions += { + case e: MouseClicked => printDebugData(table) + } + } + + //Create the scroll pane and add the table to it. + val scrollPane = new ScrollPane(table) + + //Add the scroll pane to this panel. + contents += scrollPane + + private def printDebugData(table: Table): Unit = { + val numRows = table.rowCount + val numCols = table.peer.getColumnCount() + val model: javax.swing.table.TableModel = table.model + + println("Value of data: ") + for (i <- 0 until numRows) { + print(" row " + i + ":") + for (j <- 0 until numCols) { + print(" " + model.getValueAt(i, j)) + } + println() + } + println("--------------------------") + } +} + +object SimpleTableSelectionDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "SimpleTableSelectionDemo" + //Create and set up the content pane. + val newContentPane = new SimpleTableSelectionDemo() + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala new file mode 100644 index 00000000..3e7f7cce --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala @@ -0,0 +1,153 @@ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.awt.{ AlphaComposite, Color, Composite, Graphics, Insets, RenderingHints } +import java.awt.font.FontRenderContext +import java.awt.geom.Rectangle2D +import javax.swing.Icon + +class SizeDisplayer(text: String, icon: Icon) extends Label(text, icon, Alignment.Center) { + val xTextPad = 5 + val yTextPad = 5 + opaque = true + + //Reuse textSizeD and textSizeR to avoid creating + //lots of unnecessary Dimensions and Rectangles. + private var textSizeR = new Rectangle() + private var textSizeD = new Dimension() + var userPreferredSize: Dimension = null + var userMinimumSize: Dimension = null + var userMaximumSize: Dimension = null + + def paintComponent(g: Graphics): Unit = { + val g2d = g.create().asInstanceOf[Graphics2D] //copy g + val minSize: Dimension = peer.getMinimumSize(); + val prefSize: Dimension = peer.getPreferredSize(); + val size: Dimension = peer.getSize(); + var prefX = 0 + var prefY = 0; + + //Set hints so text looks nice. + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON) + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY) + + //Draw the maximum size rectangle if we're opaque. + if (opaque) { + g2d.setColor(super.background) + g2d.fillRect(0, 0, size.width, size.height) + } + + //Draw the icon. + if (icon != null) { + val oldComposite: Composite = g2d.getComposite(); + g2d.setComposite(AlphaComposite.getInstance( + AlphaComposite.SRC_OVER, + 0.1f)) + icon.paintIcon(peer, g2d, + (size.width - icon.getIconWidth()) / 2, + (size.height - icon.getIconHeight()) / 2) + g2d.setComposite(oldComposite) + } + + //Draw the preferred size rectangle. + prefX = (size.width - prefSize.width) / 2 + prefY = (size.height - prefSize.height) / 2 + g2d.setColor(Color.RED) + g2d.drawRect(prefX, prefY, prefSize.width - 1, prefSize.height - 1) + + //Draw the minimum size rectangle. + if (minSize.width != prefSize.width || minSize.height != prefSize.height) { + val minX = (size.width - minSize.width) / 2 + val minY = (size.height - minSize.height) / 2 + g2d.setColor(Color.CYAN) + g2d.drawRect(minX, minY, minSize.width - 1, minSize.height - 1) + } + + //Draw the text. + if (text != null) { + val textSize: Dimension = getTextSize(g2d) + g2d.setColor(peer.getForeground()) + g2d.drawString(text, + (size.width - textSize.width) / 2, + (size.height - textSize.height) / 2 + + g2d.getFontMetrics().getAscent()) + } + g2d.dispose(); + } + + def getTextSize(g2d: Graphics2D): Dimension = { + if (text == null) { + textSizeD.setSize(0, 0); + } else { + val frc: FontRenderContext = + if (g2d != null) { + g2d.getFontRenderContext() + } else { + new FontRenderContext(null, false, false) + } + val textRect: Rectangle2D = peer.getFont().getStringBounds( + text, + frc) + textSizeR.setRect(textRect) + textSizeD.setSize(textSizeR.width, textSizeR.height) + } + textSizeD; + } + + def getMinimumSize(): Dimension = { + if (userMinimumSize != null) { //user has set the min size + userMinimumSize; + } else { + getPreferredSize(); + } + } + + def getPreferredSize(): Dimension = { + if (userPreferredSize != null) { //user has set the pref size + userPreferredSize + } else { + calculatePreferredSize() + } + } + + def getMaximumSize(): Dimension = { + if (userMaximumSize != null) { //user has set the max size + userMaximumSize + } else { + new Dimension(Integer.MAX_VALUE, + Integer.MAX_VALUE) + } + } + + def setMinimumSize(newSize: Dimension) { + userMinimumSize = newSize + } + def setPreferredSize (newSize: Dimension) { + userPreferredSize = newSize; + } + def setMaximumSize (newSize: Dimension) { + userMaximumSize = newSize; + } + + private def calculatePreferredSize(): Dimension = { + val insets: Insets = peer.getInsets() + val textSize: Dimension = getTextSize(null) + var iconWidth = 0 + var iconHeight = 0 + + if (icon != null) { + iconWidth = icon.getIconWidth() + iconHeight = icon.getIconHeight() + } + + val d = new Dimension( + Math.max(iconWidth, textSize.width + 2 * xTextPad) + + insets.left + insets.right, + Math.max(iconHeight, textSize.height + 2 * yTextPad) + + insets.top + insets.bottom); + super.preferredSize = d + d + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala new file mode 100644 index 00000000..280acdf7 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ ValueChanged, WindowDeiconified, WindowIconified } +import java.awt.Font +import java.awt.event.{ ActionEvent, ActionListener } +import javax.swing.Timer +import java.net.URL +import javax.swing.ImageIcon + +/* + * Tutorial: How to Use Sliders + * http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemoProject/src/components/SliderDemo.java + * + * SliderDemo.scala requires all the files in the /scala/swing/examples/tutorials/images/doggy + * directory. + */ +class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with ActionListener { + //Set up animation parameters. + val FpsMin = 0; + val FpsMax = 30; + val FpsInit = 15; //initial frames per second + var frameNumber = 0 + val NumFrames = 14 + val images = new Array[ImageIcon](NumFrames) + var frozen = false + var delay = 1000 / FpsInit + + val sliderLabel = new Label("Frames Per Second") { + horizontalAlignment = Alignment.Center + xAlignment = Alignment.Center + } + + val framesPerSecond = new Slider { + orientation = Orientation.Horizontal + min = FpsMin + max = FpsMax + value = FpsInit + //Turn on labels at major tick marks. + majorTickSpacing = 10 + minorTickSpacing = 1 + paintTicks = true + paintLabels = true + border = Swing.EmptyBorder(0, 0, 10, 0) + font = new Font("Serif", Font.ITALIC, 15) + } + + val picture = new Label() { + horizontalAlignment = Alignment.Center + xAlignment = Alignment.Center + Swing.Lowered + border = Swing.CompoundBorder( + Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) + } + + updatePicture(0); //display first frame + contents += sliderLabel + contents += framesPerSecond + contents += picture + border = Swing.EmptyBorder(10, 10, 10, 10) + + //Set up a timer that calls this object's action handler. + val timer = new Timer(delay, this); + timer.setInitialDelay(delay * 7); //We pause animation twice per cycle + //by restarting the timer + timer.setCoalesce(true); + + listenTo(framesPerSecond) + listenTo(window) + reactions += { + case ValueChanged(`framesPerSecond`) => + if (!framesPerSecond.adjusting) { + val fps: Int = framesPerSecond.value + if (fps == 0) { + if (!frozen) stopAnimation(); + } else { + delay = 1000 / fps + timer.setDelay(delay) + timer.setInitialDelay(delay * 10) + if (frozen) startAnimation() + } + } + case WindowIconified(`window`) => + stopAnimation() + case WindowDeiconified(`window`) => + startAnimation() + } + + startAnimation() + + def startAnimation(): Unit = { + //Start (or restart) animating! + timer.start(); + frozen = false; + } + + def stopAnimation(): Unit = { + //Stop the animating thread. + timer.stop(); + frozen = true; + } + + //Called when the Timer fires. + def actionPerformed(e: ActionEvent): Unit = { + //Advance the animation frame. + if (frameNumber == (NumFrames - 1)) { + frameNumber = 0 + } else { + frameNumber += 1 + } + + updatePicture(frameNumber); //display the next picture + + if (frameNumber == (NumFrames - 1) + || frameNumber == (NumFrames / 2 - 1)) { + timer.restart() + } + } + + /** Update the label to display the image for the current frame. */ + def updatePicture(frameNum: Int): Unit = { + //Get the image if we haven't already. + if (images(frameNumber) == null) { + images(frameNumber) = SliderDemo.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" + + frameNumber + + ".gif"); + } + + //Set the image. + if (images(frameNumber) != null) { + picture.icon = images(frameNumber) + } else { //image not found + picture.text = "image #" + frameNumber + " not found" + } + } +} + +object SliderDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "SliderDemo" + //Create and set up the content pane. + val newContentPane = new SliderDemo(this); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala new file mode 100644 index 00000000..153753df --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.{ ValueChanged, WindowDeiconified, WindowIconified } +import java.awt.event.{ ActionEvent, ActionListener } +import javax.swing.Timer +import java.net.URL +import javax.swing.ImageIcon +import scala.collection.mutable.HashMap + +/* + * Tutorial: How to Use Sliders + * http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemo2Project/src/components/SliderDemo2.java + * + * SliderDemo2.scala requires all the files in the /scala/swing/examples/tutorials/images/doggy + * directory. + */ +class SliderDemo2(window: Window) extends BorderPanel with ActionListener { + //Set up animation parameters. + val FpsMin = 0; + val FpsMax = 30; + val FpsInit = 15; //initial frames per second + var frameNumber = 0 + val NumFrames = 14 + val images = new Array[ImageIcon](NumFrames) + var frozen = false + var delay = 1000 / FpsInit + + //Create the label table. + val labelTable = new HashMap[Int, Label]() + labelTable += 0 -> new Label("Stop") + val slow = FpsMax/10 + labelTable += slow -> new Label("Slow") + labelTable += FpsMax -> new Label("Fast") + + val framesPerSecond = new Slider { + orientation = Orientation.Vertical + min = FpsMin + max = FpsMax + value = FpsInit + //Turn on labels at major tick marks. + majorTickSpacing = 10 + paintLabels = true + paintTicks = true + labels = labelTable + } + + val picture = new Label() { + horizontalAlignment = Alignment.Center + xAlignment = Alignment.Center + Swing.Lowered + border = Swing.CompoundBorder( + Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) + } + + updatePicture(0); //display first frame + layout(framesPerSecond) = BorderPanel.Position.West + layout(picture) = BorderPanel.Position.Center + border = Swing.EmptyBorder(10, 10, 10, 10) + + //Set up a timer that calls this object's action handler. + val timer = new Timer(delay, this); + timer.setInitialDelay(delay * 7); //We pause animation twice per cycle + //by restarting the timer + timer.setCoalesce(true); + + listenTo(framesPerSecond) + listenTo(window) + reactions += { + case ValueChanged(`framesPerSecond`) => + if (!framesPerSecond.adjusting) { + val fps: Int = framesPerSecond.value + if (fps == 0) { + if (!frozen) stopAnimation(); + } else { + delay = 1000 / fps + timer.setDelay(delay) + timer.setInitialDelay(delay * 10) + if (frozen) startAnimation() + } + } + case WindowIconified(`window`) => + stopAnimation() + case WindowDeiconified(`window`) => + startAnimation() + } + + startAnimation() + + def startAnimation(): Unit = { + //Start (or restart) animating! + timer.start(); + frozen = false; + } + + def stopAnimation(): Unit = { + //Stop the animating thread. + timer.stop(); + frozen = true; + } + + //Called when the Timer fires. + def actionPerformed(e: ActionEvent): Unit = { + //Advance the animation frame. + if (frameNumber == (NumFrames - 1)) { + frameNumber = 0 + } else { + frameNumber += 1 + } + + updatePicture(frameNumber); //display the next picture + + if (frameNumber == (NumFrames - 1) + || frameNumber == (NumFrames / 2 - 1)) { + timer.restart() + } + } + + /** Update the label to display the image for the current frame. */ + def updatePicture(frameNum: Int): Unit = { + //Get the image if we haven't already. + if (images(frameNumber) == null) { + images(frameNumber) = SliderDemo.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" + + frameNumber + + ".gif"); + } + + //Set the image. + if (images(frameNumber) != null) { + picture.icon = images(frameNumber) + } else { //image not found + picture.text = "image #" + frameNumber + " not found" + } + } +} + +object SliderDemo2 { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "SliderDemo2" + //Create and set up the content pane. + val newContentPane = new SliderDemo2(this); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala new file mode 100644 index 00000000..b489c05a --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.SelectionChanged +import java.awt.Font +import java.net.URL +import javax.swing.ImageIcon + +/* + * Tutorial: How to Use Split Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemoProject/src/components/SplitPaneDemo.java + */ +//SplitPaneDemo itself is not a visible component. +class SplitPaneDemo extends FlowPanel { + val imageNames: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig", + "dukeWaveRed", "kathyCosmo", "left", "middle", "right", "stickerface") + //Create the list of images and put it in a scroll pane. + val list = new ListView[String](imageNames) + list.selection.intervalMode = ListView.IntervalMode.Single + list.selectIndices(0) + // + val listScrollPane = new ScrollPane(list) + val picture = new Label() { + horizontalAlignment = Alignment.Center + } + picture.font = font.deriveFont(Font.ITALIC) + val pictureScrollPane = new ScrollPane(picture) + + //Create a split pane with the two scroll panes in it. + val splitPane = new SplitPane(Orientation.Horizontal, listScrollPane, pictureScrollPane) { + oneTouchExpandable = true + dividerLocation = 150 + } + + // Provide minimum sizes for the two components in the split pane. + listScrollPane.minimumSize = new Dimension(100, 50) + pictureScrollPane.minimumSize = new Dimension(400, 200) + updateLabel(imageNames(list.selection.leadIndex)) + listenTo(list.selection) + + reactions += { + case SelectionChanged(`list`) => + updateLabel(imageNames(list.selection.leadIndex)) + } + + //Renders the selected image + def updateLabel (name: String): Unit = { + val icon: ImageIcon = SplitPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + name + ".gif"); + picture.icon = icon + if (icon != null) { + picture.text = null + } else { + picture.text = "Image not found" + } + } + + //Used by SplitPaneDemo2 + def getImageList(): ListView[String] = { + list; + } + + def getSplitPane(): SplitPane = { + splitPane; + } +} + +object SplitPaneDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "SplitPaneDemo" + //Create and set up the content pane. + val newContentPane = new SplitPaneDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala new file mode 100644 index 00000000..2bf9c822 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.SelectionChanged +import java.net.URL +import javax.swing.ImageIcon + +/* + * How to Use Split Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemo2Project/src/components/SplitPaneDemo2.java + */ +class SplitPaneDemo2 extends Frame { + title = "SplitPaneDemo2" + + //Create an instance of SplitPaneDemo. + val splitPaneDemo = new SplitPaneDemo() + val top: SplitPane = splitPaneDemo.getSplitPane() + val listMe: ListView[String] = splitPaneDemo.getImageList() + + //XXXX: Bug #4131528, borders on nested split panes accumulate. + //Workaround: Set the border on any split pane within + //another split pane to null. Components within nested split + //panes need to have their own border for this to work well. + top.border = null + + //Create a regular old label + val label = new Label("Click on an image name in the list.") { + horizontalAlignment = Alignment.Center + } + + //Create a split pane and put "top" (a split pane) + //and JLabel instance in it. + val splitPane = new SplitPane(Orientation.Vertical, top, label) { + oneTouchExpandable = true + dividerLocation = 180 + } + + //Provide minimum sizes for the two components in the split pane + top.minimumSize = new Dimension(100, 50) + label.minimumSize = new Dimension(100, 30) + + //Add the split pane to this frame + contents = splitPane + + listenTo(splitPaneDemo.getImageList().selection) + + reactions += { + case (e: SelectionChanged) => + val theList: ListView[String] = e.source.asInstanceOf[ListView[String]] + if (!theList.selection.adjusting) { + if (theList.selection.leadIndex < 0) + label.text = "Nothing selected." + } else { + val index = theList.selection.leadIndex + label.text = "Selected image number " + index + } + } + +} + +object SplitPaneDemo2 { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new SplitPaneDemo2() { + title = "SplitPaneDemo2" + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala new file mode 100644 index 00000000..ada1f202 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.Font +import java.net.URL +import javax.swing.ImageIcon + +/* + * How to Use Split Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SplitPaneDividerDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SizeDisplayer.java + * + * SplitPaneDividerDemo.scala requires the following files: + * SizeDisplayer.scala + * /scala/swing/examples/tutorials/images/Cat.gif + * /scala/swing/examples/tutorials/images/Dog.gif + */ +class SplitPaneDividerDemo extends BorderPanel { + font = new Font("Serif", Font.ITALIC, 24) + val icon1 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Cat.gif") + val sd1 = new SizeDisplayer("left", icon1) { + font = font + } + sd1.setMinimumSize(new Dimension(30,30)) + + val icon2 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Dog.gif") + val sd2 = new SizeDisplayer("right", icon2) { + font = font + } + sd2.setMinimumSize(new Dimension(30,30)) + + val splitPane = new SplitPane(Orientation.Horizontal, sd1, sd2) { + resizeWeight = 0.5 + oneTouchExpandable = true + continuousLayout = true + } + + layout(splitPane) = BorderPanel.Position.Center + layout(createControlPanel) = BorderPanel.Position.South + + private def createControlPanel: Component = { + val panel = new FlowPanel() + val reset = new Button("Reset") + panel.contents += reset + + listenTo(reset) + reactions += { + case ButtonClicked(`reset`) => splitPane.resetToPreferredSizes() + } + return panel + } +} + +object SplitPaneDividerDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "SplitPaneDividerDemo" + //Create and set up the content pane. + val newContentPane = new SplitPaneDividerDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala new file mode 100644 index 00000000..0c08b2ed --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.net.URL +import javax.swing.ImageIcon + +/* + * How to Use Split Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabbedPaneDemoProject/src/components/TabbedPaneDemo.java + * + * TabbedPaneDemo.scala requires one additional file: + * /scala/swing/examples/tutorials/images/middle.gif. + */ +class TabbedPaneDemo extends GridPanel(1, 1) { + val tabbedPane = new TabbedPane() + val icon1: ImageIcon = TabbedPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val panel1: Panel = makeTextPanel("Panel #1") + tabbedPane.pages += new TabbedPane.Page("Tab 1", panel1, "Does nothing") + tabbedPane.pages(0).mnemonic = 1 + val panel2: Panel = makeTextPanel("Panel #2") + tabbedPane.pages += new TabbedPane.Page("Tab 2", panel2, "Does twice as much nothing") + tabbedPane.pages(1).mnemonic = 2 + val panel3: Panel = makeTextPanel("Panel #3") + tabbedPane.pages += new TabbedPane.Page("Tab 3", panel3, "Still does nothing") + tabbedPane.pages(2).mnemonic = 3 + val panel4: Panel = makeTextPanel("Panel #4 (has a preferred size of 410 x 50).") + panel4.preferredSize = new Dimension(410, 50) + tabbedPane.pages += new TabbedPane.Page("Tab 4", panel4, "Does nothing at all") + tabbedPane.pages(3).mnemonic = 4 + + //Add the tabbed pane to this panel. + contents += tabbedPane + + //The following line enables to use scrolling tabs. + tabbedPane.tabLayoutPolicy = TabbedPane.Layout.Scroll + + def makeTextPanel(text: String): Panel = { + val panel = new FlowPanel() + panel.peer.setDoubleBuffered(false) + val filler = new Label(text) { + horizontalAlignment = Alignment.Center + } + panel.contents += filler + panel + } +} + +object TabbedPaneDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): ImageIcon = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + // scala swing has no mechanism for setting the description. + new javax.swing.ImageIcon(imgURL) + } else { + null + } + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TabbedPaneDemo" + //Create and set up the content pane. + val newContentPane = new TabbedPaneDemo(); + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala new file mode 100644 index 00000000..a7d7d12a --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala @@ -0,0 +1,160 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.MouseClicked +import javax.swing.table.DefaultTableModel + +/* + * Tutorial: How to Use Tables + * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableDemoProject/src/components/TableDemo.java + * + * TableDemo.scala requires no other files. + * + * TableDemo is just like SimpleTableDemo, except that it uses a custom TableModel. + */ +class TableDemo extends GridPanel(1, 0) { + private val Debug = false + + val table = new Table(5, 5) { + model = new MyTableModel() + preferredViewportSize = new Dimension(500, 70) + } + table.peer.setFillsViewportHeight(true) + if (Debug) { + listenTo(table) + reactions += { + case e: MouseClicked => table.model.asInstanceOf[MyTableModel].printDebugData(table) + } + } + + //Create the scroll pane and add the table to it. + val scrollPane = new ScrollPane(table) + + //Add the scroll pane to this panel. + contents += scrollPane + class MyTableModel extends DefaultTableModel { + val columnNames: Array[String] = Array("First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) + data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) + data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) + data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) + data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) + data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + + override def getColumnCount(): Int = { columnNames.length } + override def getRowCount(): Int = { if (data == null) 0 else data.length } + override def getColumnName(col: Int): String = { columnNames(col) } + override def getValueAt(row: Int, col: Int): Object = { + col match { + case 0 => data(row)(col).asInstanceOf[String] + case 1 => data(row)(col).asInstanceOf[String] + case 2 => data(row)(col).asInstanceOf[String] + case 3 => data(row)(col).asInstanceOf[java.lang.Integer] + case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] + } + } + /* + * Don't need to implement this method unless your table's + * data can change. + */ + override def setValueAt(value: Object, row: Int, col: Int): Unit = { + if (Debug) { + println("Setting value at " + row + "," + col + + " to " + value + + " (an instance of " + + value.getClass() + ")") + } + data(row)(col) = value + fireTableCellUpdated(row, col) + if (Debug) { + println("New value of data:") + printDebugData(table) + } + } + def printDebugData(table: Table): Unit = { + val numRows = table.rowCount + val numCols = table.peer.getColumnCount() + val model: javax.swing.table.TableModel = table.model + + println("Value of data: ") + for (i <- 0 until numRows) { + System.out.print(" row " + i + ":") + for (j <- 0 until numCols) { + print(" " + model.getValueAt(i, j)) + } + println() + } + println("--------------------------") + } + } +} + +object TableDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TableDemo" + //Create and set up the content pane. + val newContentPane = new TableDemo() + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala new file mode 100644 index 00000000..8cc1ea92 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala @@ -0,0 +1,169 @@ + +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import javax.swing.table.DefaultTableModel + +/* + * Tutorial: How to Use Tables + * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/TableFTFEditDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/IntegerEditor.java + * + * TableFTFEditDemo.scala requires one other file: + * IntegerEditor.java + * + * This is exactly like TableDemo, except that it uses a + * custom cell editor to validate integer input. + */ +class TableFTFEditDemo extends GridPanel(1, 0) { + private val Debug = false + val table = new Table(5, 5) { + model = new MyTableModel() + preferredViewportSize = new Dimension(500, 70) + } + table.peer.setFillsViewportHeight(true) + + //Create the scroll pane and add the table to it. + val scrollPane = new ScrollPane(table) + + //Set up stricter input validation for the integer column. + table.peer.setDefaultEditor(Class.forName("java.lang.Integer"), + new IntegerEditor(0, 100)); + + //If we didn't want this editor to be used for other + //Integer columns, we'd do this: + //table.getColumnModel().getColumn(3).setCellEditor( + // new IntegerEditor(0, 100)); + + //Add the scroll pane to this panel. + contents += scrollPane + class MyTableModel extends DefaultTableModel { + val columnNames: Array[String] = Array("First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) + data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) + data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) + data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) + data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) + data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + + override def getColumnCount(): Int = { columnNames.length } + override def getRowCount(): Int = { if (data == null) 0 else data.length } + override def getColumnName(col: Int): String = { columnNames(col) } + override def getValueAt(row: Int, col: Int): Object = { + col match { + case 0 => data(row)(col).asInstanceOf[String] + case 1 => data(row)(col).asInstanceOf[String] + case 2 => data(row)(col).asInstanceOf[String] + case 3 => data(row)(col).asInstanceOf[java.lang.Integer] + case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] + } + } + + override def getColumnClass(c: Int): Class[_] = { + getValueAt(0, c).getClass(); + } + /* + * Don't need to implement this method unless your table's + * data can change. + */ + override def setValueAt(value: Object, row: Int, col: Int): Unit = { + if (Debug) { + println("Setting value at " + row + "," + col + + " to " + value + + " (an instance of " + + value.getClass() + ")") + } + data(row)(col) = value + fireTableCellUpdated(row, col) + if (Debug) { + println("New value of data:") + printDebugData(table) + } + } + def printDebugData(table: Table): Unit = { + val numRows = table.rowCount + val numCols = table.peer.getColumnCount() + val model: javax.swing.table.TableModel = table.model + + println("Value of data: ") + for (i <- 0 until numRows) { + System.out.print(" row " + i + ":") + for (j <- 0 until numCols) { + print(" " + model.getValueAt(i, j)) + } + println() + } + println("--------------------------") + } + } +} + +object TableFTFEditDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TableFTFEditDemo" + //Create and set up the content pane. + val newContentPane = new TableFTFEditDemo() + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala new file mode 100644 index 00000000..6367615a --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.ButtonClicked +import javax.swing.table.DefaultTableModel +import java.text.MessageFormat + +/* + * Tutorial: How to Use Tables + * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TablePrintDemoProject/src/components/TablePrintDemo.java + * + * TablePrintDemo.scala requires no other files. + */ +class TablePrintDemo extends BoxPanel(Orientation.Vertical) { + private val Debug = false + + val table = new Table(5, 5) { + model = new MyTableModel() + preferredViewportSize = new Dimension(500, 70) + } + table.peer.setFillsViewportHeight(true) + // if (Debug) { + // listenTo(table) + // reactions += { + // case e: MouseClicked => printDebugData(table) + // } + // } + + //Create the scroll pane and add the table to it. + val scrollPane = new ScrollPane(table) + + //Add a print button. + val printButton = new Button("Print") { + // xAlignment = Alignment.Center + peer.setAlignmentX(0.5f) + } + + //Add the scroll pane to this panel. + contents += scrollPane + contents += printButton + + listenTo(printButton) + reactions += { + case ButtonClicked(`printButton`) => + val header: MessageFormat = new MessageFormat("Page {0, number, integer}") + try { + table.peer.print(javax.swing.JTable.PrintMode.FIT_WIDTH, header, null) + } catch { + case e: java.awt.print.PrinterException => + //sys.err does not have a print method + System.err.format("Cannot print %s%n", e.getMessage()) + } + } + + class MyTableModel extends DefaultTableModel { + val columnNames: Array[String] = Array("First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) + data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) + data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) + data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) + data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) + data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + + override def getColumnCount(): Int = { columnNames.length } + override def getRowCount(): Int = { if (data == null) 0 else data.length } + override def getColumnName(col: Int): String = { columnNames(col) } + override def getValueAt(row: Int, col: Int): Object = { + col match { + case 0 => data(row)(col).asInstanceOf[String] + case 1 => data(row)(col).asInstanceOf[String] + case 2 => data(row)(col).asInstanceOf[String] + case 3 => data(row)(col).asInstanceOf[java.lang.Integer] + case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] + } + } + /* + * Don't need to implement this method unless your table's + * data can change. + */ + override def setValueAt(value: Object, row: Int, col: Int): Unit = { + if (Debug) { + println("Setting value at " + row + "," + col + + " to " + value + + " (an instance of " + + value.getClass() + ")") + } + data(row)(col) = value + fireTableCellUpdated(row, col) + if (Debug) { + println("New value of data:") + printDebugData(table) + } + } + def printDebugData(table: Table): Unit = { + val numRows = table.rowCount + val numCols = table.peer.getColumnCount() + val model: javax.swing.table.TableModel = table.model + + println("Value of data: ") + for (i <- 0 until numRows) { + System.out.print(" row " + i + ":") + for (j <- 0 until numCols) { + print(" " + model.getValueAt(i, j)) + } + println() + } + println("--------------------------") + } + } + +} + +object TablePrintDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TablePrintDemo" + //Create and set up the content pane. + val newContentPane = new TablePrintDemo() + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala new file mode 100644 index 00000000..11132226 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + + + +import scala.swing._ +import scala.swing.event.ButtonClicked +import javax.swing.event.{ListSelectionEvent, ListSelectionListener} +import javax.swing.table.DefaultTableModel + +/* + * Tutorial: How to Use Tables + * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSelectionDemoProject/src/components/TableSelectionDemo.java + * + * TableSelectionDemo.scala requires no other files. + */ +class TableSelectionDemo extends BoxPanel(Orientation.Vertical) { + + val table = new Table(5, 5) { + model = new MyTableModel() + preferredViewportSize = new Dimension(500, 70) + } + table.peer.setFillsViewportHeight(true) + table.peer.getSelectionModel().addListSelectionListener(new RowListener()) + table.peer.getColumnModel().getSelectionModel(). + addListSelectionListener(new ColumnListener()); + //Create the scroll pane and add the table to it. + val scrollPane = new ScrollPane(table) + + contents += new Label("Selection Mode") + + val multipleInterval = new RadioButton("Multiple Interval Selection") { + selected = true + } + val single = new RadioButton("Single Selection") + val singleInterval = new RadioButton("Single Interval Selection") + val buttonGroup = new ButtonGroup() { + buttons += multipleInterval + buttons += single + buttons += singleInterval + } + contents += multipleInterval + contents += single + contents += singleInterval + + contents += new Label("Selection Options") + val rowCheck = new CheckBox("Row Selection") { + selected = true + } + val columnCheck = new CheckBox("Column Selection") + val cellCheck = new CheckBox("Cell Selection") { + enabled = false + } + contents += rowCheck + contents += columnCheck + contents += cellCheck + + //Add the scroll pane to this panel. + contents += scrollPane + + val output = new TextArea(5, 40) { + editable = false + } + + contents += new ScrollPane(output) + + listenTo(multipleInterval) + listenTo(single) + listenTo(singleInterval) + listenTo(rowCheck) + listenTo(columnCheck) + listenTo(cellCheck) + + reactions += { + case ButtonClicked(`rowCheck`) => + //Scala swing does not allow cell selection to be set independently. + if (rowCheck.selected) { + table.selection.elementMode = Table.ElementMode.Row + columnCheck.selected = false + cellCheck.selected = false + } + else { + table.selection.elementMode = Table.ElementMode.None + } + case ButtonClicked(`columnCheck`) => + //Scala swing does not allow cell selection to be set independently. + if (columnCheck.selected) { + table.selection.elementMode = Table.ElementMode.Column + rowCheck.selected = false + cellCheck.selected = false + } + else { + table.selection.elementMode = Table.ElementMode.None + } + case ButtonClicked(`cellCheck`) => + //Scala swing does not allow cell selection to be set independently. + if (cellCheck.selected) { + table.selection.elementMode = Table.ElementMode.Cell + rowCheck.selected = false + columnCheck.selected = false + } + else { + table.selection.elementMode = Table.ElementMode.None + } + case ButtonClicked(`multipleInterval`) => + table.selection.intervalMode = Table.IntervalMode.MultiInterval + //If cell selection is on, turn it off. + if (cellCheck.selected) { + cellCheck.selected = false + cellCheck.enabled = false + table.selection.elementMode = Table.ElementMode.None + } + case ButtonClicked(`singleInterval`) => + table.selection.intervalMode = Table.IntervalMode.SingleInterval + cellCheck.enabled = true + case ButtonClicked(`single`) => + table.selection.intervalMode = Table.IntervalMode.Single + cellCheck.enabled = true + } + + def outputSelection(): Unit = { + output.append("Lead: %d, %d. ".format( + table.peer.getSelectionModel().getLeadSelectionIndex(), + table.peer.getColumnModel().getSelectionModel(). + getLeadSelectionIndex())); + output.append("Rows:"); + for (c: Int <- table.selection.rows) { + output.append(" " + c.asInstanceOf[Int]) + } + output.append(". Columns:"); + for (c: Int <- table.selection.columns) { + output.append(" " + c.asInstanceOf[Int]) + } + output.append(".\n"); + } + + class RowListener extends ListSelectionListener { + def valueChanged(event: ListSelectionEvent): Unit = { + if (!event.getValueIsAdjusting()) { + output.append("ROW SELECTION EVENT. ") + outputSelection() + } + } + } + + class ColumnListener extends ListSelectionListener { + def valueChanged(event: ListSelectionEvent): Unit = { + if (!event.getValueIsAdjusting()) { + output.append("COLUMN SELECTION EVENT. ") + outputSelection() + } + } + } + + class MyTableModel extends DefaultTableModel { + val columnNames: Array[String] = Array("First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) + data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) + data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) + data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) + data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) + data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + + override def getColumnCount(): Int = { columnNames.length } + override def getRowCount(): Int = { if (data == null) 0 else data.length } + override def getColumnName(col: Int): String = { columnNames(col) } + override def getValueAt(row: Int, col: Int): Object = { + col match { + case 0 => data(row)(col).asInstanceOf[String] + case 1 => data(row)(col).asInstanceOf[String] + case 2 => data(row)(col).asInstanceOf[String] + case 3 => data(row)(col).asInstanceOf[java.lang.Integer] + case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] + } + } + + override def getColumnClass(c: Int): Class[_] = { + getValueAt(0, c).getClass(); + } + + /* + * Don't need to implement this method unless your table's + * editable. + */ + override def isCellEditable(row: Int, col: Int): Boolean = { + //Note that the data/cell address is constant, + //no matter where the cell appears onscreen. + if (col < 2) { + false; + } else { + true; + } + } + + /* + * Don't need to implement this method unless your table's + * data can change. + */ + override def setValueAt(value: Object, row: Int, col: Int): Unit = { + data(row)(col) = value + fireTableCellUpdated(row, col) + } + } +} + +object TableSelectionDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TableSelectionDemo" + //Create and set up the content pane. + val newContentPane = new TableSelectionDemo() + newContentPane.opaque = true //content panes must be opaque + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala new file mode 100644 index 00000000..7bff6fc6 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + + +import scala.collection.mutable.HashMap +import scala.swing._ +import scala.swing.event.CaretUpdate +import java.awt.{ Color, Dimension, Event, Insets } +import java.awt.event.KeyEvent +import javax.swing.{ InputMap, KeyStroke, SwingUtilities, UIManager } +import javax.swing.event.{DocumentEvent, DocumentListener, UndoableEditEvent, UndoableEditListener} +import javax.swing.text.{AbstractDocument, BadLocationException, DefaultEditorKit, Document, SimpleAttributeSet, StyleConstants, StyledDocument, StyledEditorKit} +import javax.swing.undo.UndoManager + +/* + * Tutorials: How to Use Text Fields + * http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html + * How to Use Actions + * http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/DocumentSizeFilter.java + * + * TextComponentDemo.scala requires one additional file: + * DocumentSizeFilter.scala + */ +class TextComponentDemo extends Frame { + private val MaxCharacters = 300 + private val newline = "\n" + title = "TextComponentDemo" + val undo: UndoManager = new UndoManager() + + //Create the text pane and configure it. + val textPane: TextPane = new TextPane() + textPane.peer.setCaretPosition(0) + textPane.peer.setMargin(new Insets(5, 5, 5, 5)) + val styledDoc: StyledDocument = textPane.styledDocument + val doc: AbstractDocument = styledDoc.asInstanceOf[AbstractDocument] + doc.setDocumentFilter(new DocumentSizeFilter(MaxCharacters)) + + val scrollPane = new ScrollPane(textPane) + scrollPane.preferredSize = new Dimension(200, 200) + + val undoAction = new UndoAction() + val redoAction = new RedoAction() + + //Create the text area for the status log and configure it. + val changeLog = new TextArea(5, 30) + changeLog.editable = false + val scrollPaneForLog = new ScrollPane(changeLog) + + //Create a split pane for the change log and the text area. + val splitPane = new SplitPane(Orientation.Horizontal, scrollPane, scrollPaneForLog) + splitPane.oneTouchExpandable = true + + //Create the status area + val caretListenerLabel = new CaretListenerLabel("Caret Status") + val statusPane = new GridPanel(1, 1) { + contents += caretListenerLabel + } + + contents = new BorderPanel() { + layout(splitPane) = BorderPanel.Position.Center + layout(statusPane) = BorderPanel.Position.South + } + + //Set up the menu bar. + val actions = createActionTable(textPane) + val editMenu: Menu = createEditMenu() + val styleMenu: Menu = createStyleMenu() + val mb: MenuBar = new MenuBar() { + contents += editMenu + contents += styleMenu + } + menuBar = mb + + //Add some key bindings. + addBindings() + + //Put the initial text into the text pane. + initDocument() + textPane.peer.setCaretPosition(0) + + //Start watching for undoable edits and caret changes. + listenTo(this) + doc.addUndoableEditListener(new MyUndoableEditListener()) + reactions += { + case CaretUpdate(textPane) => + caretListenerLabel.displaySelectionInfo(textPane.caret.dot, textPane.caret.mark) + } + doc.addDocumentListener(new MyDocumentListener()) + + override def closeOperation() = { + System.exit(0) + } + + class MyUndoableEditListener extends UndoableEditListener { + def undoableEditHappened(e: UndoableEditEvent) { + undo.addEdit(e.getEdit()) + undoAction.updateUndoState() + redoAction.updateRedoState() + } + } + + class MyDocumentListener extends DocumentListener { + def insertUpdate(e: DocumentEvent): Unit = { + displayEditInfo(e) + } + def removeUpdate(e: DocumentEvent): Unit = { + displayEditInfo(e) + } + def changedUpdate(e: DocumentEvent): Unit = { + displayEditInfo(e) + } + private def displayEditInfo(e: DocumentEvent): Unit = { + val document: Document = e.getDocument() + val changeLength = e.getLength() + changeLog.append(e.getType.toString() + ":" + + changeLength + " character" + + (if (changeLength == 1) {". "} else {"s. "}) + + " Text length = " + document.getLength() + + "." + newline) + } + } + + def addBindings(): Unit = { + val inputMap: InputMap = textPane.peer.getInputMap + //Ctrl-b to go backward one character + val keyb: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK) + inputMap.put(keyb, DefaultEditorKit.backwardAction) + //Ctrl-f to go forward one character + val keyf: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK) + inputMap.put(keyf, DefaultEditorKit.forwardAction) + //Ctrl-p to go up one line + val keyp: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK) + inputMap.put(keyp, DefaultEditorKit.upAction) + //Ctrl-n to go down one line + val keyn: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK) + inputMap.put(keyn, DefaultEditorKit.downAction) + } + + def createEditMenu(): Menu = { + val menu: Menu = new Menu("Edit") { + // undoAction = new UndoAction() + contents += new MenuItem(undoAction) + //redoAction = new RedoAction() + contents += new MenuItem(redoAction) + contents += new Separator() + //These actions come from the default editor kit. + //Get the ones we want and stick them in the menu. + // cut-to-clipboard + val oldCutAction = getActionByName(DefaultEditorKit.cutAction).get + val miCut = new MenuItem(DefaultEditorKit.cutAction) + miCut.peer.setAction(oldCutAction) + contents += miCut + // copy-to-clipboard + val oldCopyAction = getActionByName(DefaultEditorKit.copyAction).get + val miCopy = new MenuItem(DefaultEditorKit.copyAction) + miCopy.peer.setAction(oldCopyAction) + contents += miCopy + // paste-from-clipboard + val oldPasteAction = getActionByName(DefaultEditorKit.pasteAction).get + val miPaste = new MenuItem(DefaultEditorKit.pasteAction) + miPaste.peer.setAction(oldPasteAction) + contents += miPaste + // + contents += new Separator() + // select-all + val oldSelectAllAction = getActionByName(DefaultEditorKit.selectAllAction).get + val miSelectAll = new MenuItem(DefaultEditorKit.selectAllAction) + miSelectAll.peer.setAction(oldSelectAllAction) + contents += miSelectAll + } + menu + } + + def createStyleMenu(): Menu = { + val menu: Menu = new Menu("Style") { + val boldAction = new StyledEditorKit.BoldAction() + val miBold = new MenuItem("Bold") + miBold.peer.setAction(boldAction) + contents += miBold + // + val italicAction = new StyledEditorKit.ItalicAction() + val miItalic = new MenuItem("Italic") + miItalic.peer.setAction(italicAction) + contents += miItalic + // + val underlineAction = new StyledEditorKit.UnderlineAction() + val miUnderline = new MenuItem("Underline") + miUnderline.peer.setAction(underlineAction) + contents += miUnderline + // + contents += new Separator() + // + val font12Action = new StyledEditorKit.FontSizeAction("12", 12) + val miFont12 = new MenuItem("12") + miFont12.peer.setAction(font12Action) + contents += miFont12 + // + val font14Action = new StyledEditorKit.FontSizeAction("14", 14) + val miFont14 = new MenuItem("14") + miFont14.peer.setAction(font14Action) + contents += miFont14 + // + val font18Action = new StyledEditorKit.FontSizeAction("18", 18) + val miFont18 = new MenuItem("18") + miFont18.peer.setAction(font18Action) + contents += miFont18 + // + contents += new Separator() + // + val fontSerifAction = new StyledEditorKit.FontFamilyAction("Serif", "Serif") + val miFontSerif = new MenuItem("Serif") + miFontSerif.peer.setAction(fontSerifAction) + contents += miFontSerif + // + val fontSansSerifAction = new StyledEditorKit.FontFamilyAction("SansSerif", "SansSerif") + val miFontSansSerif = new MenuItem("SansSerif") + miFontSansSerif.peer.setAction(fontSansSerifAction) + contents += miFontSansSerif + // + contents += new Separator() + // + val fgRedAction = new StyledEditorKit.ForegroundAction("Red", Color.red) + val miFgRed = new MenuItem("Red") + miFgRed.peer.setAction(fgRedAction) + contents += miFgRed + // + val fgGreenAction = new StyledEditorKit.ForegroundAction("Green", Color.green) + val miFgGreen = new MenuItem("Green") + miFgGreen.peer.setAction(fgGreenAction) + contents += miFgGreen + // + val fgBlueAction = new StyledEditorKit.ForegroundAction("Blue", Color.blue) + val miFgBlue = new MenuItem("Blue") + miFgBlue.peer.setAction(fgBlueAction) + contents += miFgBlue + // + val fgBlackAction = new StyledEditorKit.ForegroundAction("Black", Color.black) + val miFgBlack = new MenuItem("Black") + miFgBlack.peer.setAction(fgBlackAction) + contents += miFgBlack + } + menu + } + + def initDocument(): Unit = { + val initString: Array[String] = + Array("Use the mouse to place the caret.", + "Use the edit menu to cut, copy, paste, and select text.", + "Also to undo and redo changes.", + "Use the style menu to change the style of the text.", + "Use the arrow keys on the keyboard or these emacs key bindings to move the caret:", + "Ctrl-f, Ctrl-b, Ctrl-n, Ctrl-p.") + + val attrs: Array[SimpleAttributeSet] = initAttributes(initString.length); + for (i <- 0 until initString.length) { + doc.insertString(doc.getLength(), initString(i) + newline, attrs(i)); + } + } + + def initAttributes(length: Int): Array[SimpleAttributeSet] = { + //Hard-code some attributes. + val attrs = new Array[SimpleAttributeSet](length) + attrs(0) = new SimpleAttributeSet() + StyleConstants.setFontFamily(attrs(0), "SansSerif") + StyleConstants.setFontSize(attrs(0), 16) + attrs(1) = new SimpleAttributeSet(attrs(0)) + StyleConstants.setBold(attrs(1), true) + attrs(2) = new SimpleAttributeSet(attrs(0)) + StyleConstants.setItalic(attrs(2), true) + attrs(3) = new SimpleAttributeSet(attrs(0)) + StyleConstants.setFontSize(attrs(3), 20) + attrs(4) = new SimpleAttributeSet(attrs(0)) + StyleConstants.setFontSize(attrs(4), 12) + attrs(5) = new SimpleAttributeSet(attrs(0)) + StyleConstants.setForeground(attrs(5), Color.red) + attrs + } + + //The following two methods allow us to find an + //action provided by the editor kit by its name. + def createActionTable(textComponent: TextComponent): HashMap[String, javax.swing.Action] = { + var hm = new HashMap[String, javax.swing.Action]() + for (a <- textComponent.peer.getActions()) { + val s = a.getValue(javax.swing.Action.NAME).asInstanceOf[String] + hm.put(s, a) + } + hm + } + + def getActionByName(name: String): Option[javax.swing.Action] = { + actions.get(name) + } + + // javax.swing.event.UndoableEditEvent + // + class UndoAction extends Action("Undo") { + + def apply = {} + + enabled = false + + def updateUndoState(): Unit = { + if (undo.canUndo()) { + enabled = true + // putValue(Action.NAME, undo.getUndoPresentationName()) + } else { + enabled = false + // putValue(Action.NAME, "Undo") + } + } + } + + class RedoAction extends Action("Redo") { + enabled = false + + def apply = {} + + def updateRedoState(): Unit = { + if (undo.canRedo()) { + enabled = true + // putValue(Action.NAME, undo.getRedoPresentationName()) + } else { + enabled = false + // putValue(Action.NAME, "Redo") + } + } + } + + class CaretListenerLabel(label: String) extends Label(label) { + private val newline = "\n" + text = label + //This method can be invoked from any thread. It + //invokes the setText and modelToView methods, which + //must run on the event dispatch thread. We use + //invokeLater to schedule the code for execution + //on the event dispatch thread. + def displaySelectionInfo(dot: Int, mark: Int): Unit = { + SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + if (dot == mark) { // no selection + try { + val caretCoords: Rectangle = textPane.peer.modelToView(dot) + //Convert it to view coordinates. + text = "caret: text position: " + dot + ", view location = [" + + caretCoords.x + ", " + caretCoords.y + "]" + newline + } catch { + case ble: BadLocationException => + text = "selection from: " + mark + " to " + dot + newline + } + } else if (dot < mark) { + text = "selection from: " + dot + " to " + mark + newline + } else { + text = "selection from: " + mark + " to " + dot + newline + } + } + }) + } + } + +} + +object TextComponentDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event dispatch thread. + */ + def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame = new TextComponentDemo(); + + //Display the window. + frame.pack(); + frame.visible = true + } + + //The standard main method. + def main(args: Array[String]): Unit = { + //Schedule a job for the event dispatch thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + //Turn off metal's use of bold fonts + UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }); + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala new file mode 100644 index 00000000..92f9d579 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import scala.swing.event.EditDone + +/* + * Tutorials: How to Use Text Fields + * http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html + * How to Use Text Areas + * http://docs.oracle.com/javase/tutorial/uiswing/components/textarea.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextDemoProject/src/components/TextDemo.java + * + * TextDemo.scala requires no other files. + */ +class TextDemo extends GridBagPanel { + private val newline = "\n" + val textField = new TextField(20) + val textArea = new TextArea(5, 20) { + editable = false + } + val scrollPane = new ScrollPane(textArea) + + //Add Components to this panel. + val c: Constraints = new Constraints() + + c.gridwidth = java.awt.GridBagConstraints.REMAINDER + c.fill = GridBagPanel.Fill.Horizontal + layout(textField) = c + c.fill = GridBagPanel.Fill.Both + c.weightx = 1.0 + c.weighty = 1.0 + layout(scrollPane) = c + + listenTo(textField) + reactions += { + case EditDone(`textField`) => + textArea.text += textField.text + newline + textField.selectAll() + //Make sure the new text is visible, even if there + //was a selection in the text area. + textArea.caret.position = textArea.peer.getDocument().getLength() + } +} + +object TextDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event dispatch thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TextDemo" + //Create and set up the content pane. + val newContentPane = new TextDemo() + contents = newContentPane + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + //The standard main method. + def main(args: Array[String]): Unit = { + //Schedule a job for the event dispatch thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }); + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala new file mode 100644 index 00000000..a09ba427 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -0,0 +1,326 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components + +import java.awt.{ Cursor, Font, Toolkit } +import javax.swing.text.{ StyleConstants, StyleContext } +import scala.swing._ +import scala.swing.event._ + +/* + * Tutorials: How to Use Text Components + * http://docs.oracle.com/javase/tutorial/uiswing/components/text.html + * How to Use Editor Panes and Text Panes + * http://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextSamplerDemoProject/src/components/TextSamplerDemo.java + * + * TextSamplerDemo.scala requires the following files: + * TextSamplerDemoHelp.html (which references images/dukeWaveRed.gif) + * /scala/swing/examples/tutorials/images/Pig.gif + * /scala/swing/examples/tutorials/images/sound.gif + */ +object TextSamplerDemo { + val newline = "\n" + + def createAndShowGUI(): Unit = { + val top = new Frame() { + title = "TextSamplerDemo" + + private val textFieldString = "TextField" + private val passwordFieldString = "PasswordField" + private val ftfString = "FormattedTextField" + private val buttonString = "Button" + + val button = new Button() + + //Create a regular text field. + val textField = new TextField(10) + + //Create a password field. + val passwordField = new PasswordField(10) + + //Create a formatted text field. + val ftf = new FormattedTextField(java.text.DateFormat.getDateInstance()) + // Had to use the peer for this purpose.......................................... + ftf.peer.setValue(java.util.Calendar.getInstance().getTime()) + + //Create some labels for the fields. + val textFieldLabel = new Label(textFieldString + ": ") + // textFieldLabel.setLabelFor(textField) + val passwordFieldLabel = new Label(passwordFieldString + ": ") + val ftfLabel = new Label(ftfString + ": ") + // ftfLabel.setLabelFor(ftf) + + //Create a label to put messages during an action event. + val actionLabel = new Label("Type text in a field and press Enter.") + actionLabel.border = Swing.EmptyBorder(10, 0, 0, 0) + + //Lay out the text controls and the labels. + val textControlsPane = new GridBagPanel { + val c: Constraints = new Constraints() + + c.gridwidth = java.awt.GridBagConstraints.RELATIVE + c.fill = GridBagPanel.Fill.None + c.weightx = 0.0 + layout(textFieldLabel) = c + + c.gridwidth = java.awt.GridBagConstraints.REMAINDER + c.fill = GridBagPanel.Fill.Horizontal + c.weightx = 1.0 + layout(textField) = c + + c.gridwidth = java.awt.GridBagConstraints.RELATIVE + c.fill = GridBagPanel.Fill.None + c.weightx = 0.0 + layout(passwordFieldLabel) = c + + c.gridwidth = java.awt.GridBagConstraints.REMAINDER + c.fill = GridBagPanel.Fill.Horizontal + c.weightx = 1.0 + layout(passwordField) = c + + c.gridwidth = java.awt.GridBagConstraints.RELATIVE + c.fill = GridBagPanel.Fill.None + c.weightx = 0.0 + layout(ftfLabel) = c + + c.gridwidth = java.awt.GridBagConstraints.REMAINDER + c.fill = GridBagPanel.Fill.Horizontal + c.weightx = 1.0 + layout(ftf) = c + + c.gridwidth = java.awt.GridBagConstraints.REMAINDER // last + c.anchor = GridBagPanel.Anchor.West + c.weightx = 1.0 + layout(actionLabel) = c + + border = Swing.CompoundBorder( + Swing.TitledBorder(Swing.EmptyBorder, "Text Fields"), + Swing.EmptyBorder(5, 5, 5, 5)) + } + + //Create a text area. + val textArea = new TextArea( + "This is an editable JTextArea. " + + "A text area is a \"plain\" text component, " + + "which means that although it can display text " + + "in any font, all of the text is in the same font.") + textArea.font = new Font("Serif", Font.ITALIC, 16) + textArea.lineWrap = true + textArea.wordWrap = true + + //Put the text area in a scrollpane + val areaScrollPane: ScrollPane = new ScrollPane(textArea) + areaScrollPane.verticalScrollBarPolicy = ScrollPane.BarPolicy.Always + areaScrollPane.preferredSize = new Dimension(250, 250) + areaScrollPane.border = + Swing.CompoundBorder( + Swing.CompoundBorder( + Swing.TitledBorder(Swing.EmptyBorder, "Plain Text"), + Swing.EmptyBorder(5, 5, 5, 5)), areaScrollPane.border) + + //Create an editor pane. + val editorPane: EditorPane = new EditorPane() + editorPane.editable = false + //To get this to work in Eclipse, add /src/main/resources directory to the run + //configuration classpath. The file TextSamplerDemoHelp.html is placed in that + //directory. + val helpURL: java.net.URL = getClass().getResource("/scala/swing/examples/tutorials/TextSamplerDemoHelp.html") + + if (helpURL != null) { + editorPane.editorKit = new javax.swing.text.html.HTMLEditorKit + editorPane.contentType = "text/html" + // Had to reach into the peer for this................... + editorPane.peer.setPage(helpURL) + } else { + textField.text = "TextSampleDemoHelp.html was not found." + } + + val editorScrollPane = new ScrollPane(editorPane) + editorScrollPane.verticalScrollBarPolicy = ScrollPane.BarPolicy.Always + editorScrollPane.preferredSize = new java.awt.Dimension(250, 145) + editorScrollPane.minimumSize = new java.awt.Dimension(10, 10) + + //Create a text pane and put it into a scrollpane. + // JTextPane has no analogue in scala.swing + // val textPane:TextPane = new TextPane() + val textPane: TextPane = createTextPane(button) + + val paneScrollPane = new ScrollPane(textPane) + + paneScrollPane.verticalScrollBarPolicy = ScrollPane.BarPolicy.Always + paneScrollPane.preferredSize = new java.awt.Dimension(250, 155) + paneScrollPane.minimumSize = new java.awt.Dimension(10, 10) + + //Put the editor pane and the text pane in a split pane. + //Use Orientation.Horizontal instead of JSplitPane.VERTICAL_SPLIT + val splitPane = new SplitPane(Orientation.Horizontal, + editorScrollPane, paneScrollPane) + splitPane.oneTouchExpandable = true + splitPane.resizeWeight = 0.5 + + //Place the splitpane in a panel destined for the right of the screen + val rightPane = new GridPanel(1, 0) { + contents += splitPane + border = Swing.CompoundBorder( + Swing.TitledBorder(Swing.EmptyBorder, "Styled Text"), + Swing.EmptyBorder(5, 5, 5, 5)) + } + + //Place the text and area controls in a panel destined for the left + // of the screen + val leftPane = new BorderPanel() { + layout(textControlsPane) = BorderPanel.Position.North + layout(areaScrollPane) = BorderPanel.Position.Center + } + + listenTo(textField) + listenTo(passwordField) + listenTo(button) + val prefix = "You typed \"" + reactions += { + case EditDone(`textField`) => + actionLabel.text = prefix + textField.text + "\"" + case EditDone(`passwordField`) => + actionLabel.text = prefix + passwordField.password + "\"" + case ButtonClicked(`button`) => + Toolkit.getDefaultToolkit().beep() // No sound heard... + actionLabel.text = "Beep?!" + } + + contents = new BorderPanel() { + layout(leftPane) = BorderPanel.Position.West + layout(rightPane) = BorderPanel.Position.East + } + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + + } + + def addStylesToDocument(doc: javax.swing.text.StyledDocument, button: Button): Unit = { + val `def` = StyleContext.getDefaultStyleContext.getStyle(StyleContext.DEFAULT_STYLE) + val regular = doc.addStyle("regular", `def`) + StyleConstants.setFontFamily(`def`, "SansSerif") + var s = doc.addStyle("italic", regular) + StyleConstants.setItalic(s, true) + s = doc.addStyle("bold", regular) + StyleConstants.setBold(s, true) + s = doc.addStyle("small", regular) + StyleConstants.setFontSize(s, 10) + s = doc.addStyle("large", regular) + StyleConstants.setFontSize(s, 16) + s = doc.addStyle("icon", regular) + StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER) + val pigIcon = createImageIcon("/scala/swing/examples/tutorials/images/Pig.gif", "a cute pig") + if (pigIcon != None) { + StyleConstants.setIcon(s, pigIcon.get) + } + s = doc.addStyle("button", regular) + StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER) + val soundIcon = createImageIcon("/scala/swing/examples/tutorials/images/sound.gif", "sound icon") + // button = new Button() + if (soundIcon != None) { + button.icon = soundIcon.get + } else { + button.text = "BEEP" + } + button.cursor = Cursor.getDefaultCursor + button.margin = new Insets(0, 0, 0, 0) + // button.setActionCommand(buttonString) + // button.addActionListener(this) + StyleConstants.setComponent(s, button.peer) + } + + def createTextPane(button: Button): TextPane = { + val initStrings: Array[String] = Array( + "This is an editable JTextPane, ", //regular + "another ", //italic + "styled ", //bold + "text ", //small + "component, ", //large + "which supports embedded components..." + newline, //regular + " " + newline, //button + "...and embedded icons..." + newline, //regular + " ", //icon + newline + "JTextPane is a subclass of JEditorPane that " + + "uses a StyledEditorKit and StyledDocument, and provides " + + "cover methods for interacting with those objects.") + val initStyles: Array[String] = Array( + "regular", "italic", "bold", "small", "large", + "regular", "button", "regular", "icon", + "regular") + val textPane = new TextPane() + val doc: javax.swing.text.StyledDocument = textPane.styledDocument + addStylesToDocument(doc, button) + for (i <- 0 until initStrings.length) { + doc.insertString(doc.getLength(), initStrings(i), doc.getStyle(initStyles(i))) + } + textPane + } + + private def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { + val imgURL: java.net.URL = getClass().getResource(path) + val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { + Some(new javax.swing.ImageIcon(imgURL, description)) + } else { + None + } + img + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + javax.swing.UIManager.put("swing.boldMetal", false) + createAndShowGUI() + } + }) + } +} + + +class TextPane() extends TextComponent { + override lazy val peer: javax.swing.JTextPane = new javax.swing.JTextPane() with SuperMixin + def styledDocument: javax.swing.text.StyledDocument = peer.getStyledDocument() +} + + + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala new file mode 100644 index 00000000..15cfe0fb --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ + +/* + * Tutorial: Using Top-Level Containers + * http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TopLevelDemoProject/src/components/TopLevelDemo.java + * + * TopLevelDemo.scala requires no other files. + */ +object TopLevelDemo { + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + private def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "TopLevelDemo" + + //Create the menu bar. Make it have a green background. + val greenMenuBar: MenuBar = new MenuBar() { + opaque = true + background = new Color(154, 165, 127) + preferredSize = new Dimension(200, 20) + } + + //Create a yellow label to put in the content pane. + val yellowlabel = new Label("Hello World") { + opaque = true + background = new Color(248, 213, 131) + preferredSize = new Dimension(200, 180) + } + + //Set the menu bar and add the label to the content pane. + menuBar = greenMenuBar + contents = new BorderPanel { + layout(yellowlabel) = BorderPanel.Position.Center + } + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala new file mode 100644 index 00000000..2c35b7b8 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala @@ -0,0 +1,289 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.components + +import scala.swing._ +import java.io.BufferedInputStream +import java.awt.event.{ ActionEvent, ActionListener } +import java.awt.{ Color, Graphics, Graphics2D, Toolkit } +import javax.swing.{ ImageIcon, SwingUtilities, SwingWorker, Timer } + +/* + * Tutorial: How to Make Applets + * http://docs.oracle.com/javase/tutorial/uiswing/components/applet.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TumbleItemProject/src/components/TumbleItem.java + * + * @author jag + * @author mem + * @author kwalrath + * @author ir71389 + * + * TumbleItem.scala requires these files: + * all the images in the /scala/swing/examples/tutorials/images/tumble directory + * (or, if specified in the applet tag, another directory [dir] + * with images named T1.gif ... Tx.gif, where x is the total + * number of images [nimgs]) + * the appropriate code to specify that the applet be executed, + * such as the HTML code in TumbleItem.html or TumbleItem.atag, + * or the JNLP code in TumbleItem.jnlp + * + */ +class TumbleItem extends Applet { + var loopslot = -1 //the current frame number + var timer: Timer = null //the timer animating the images + var dir: String = null //the directory relative to the codebase + //from which the images are loaded + var pause: Int = 0 //the length of the pause between revs + var offset: Int = 0 //how much to offset between loops + var speed: Int = 0 //animation speed + var nimgs: Int = 0 //number of images to animate + var maxWidth: Int = 0 //width of widest image + var mywidth: Int = 0 //width of the applet's content pane + var off: Int = 0 //the current offset + var imgs: Array[ImageIcon] = null + var worker: SwingWorker[Array[ImageIcon], Void] = null + val ui = new ui() + + def loadAppletParameters(): Unit = { + //Get the applet parameters. + var at: String = getParameter("img") + dir = if (at != null) at else "/scala/swing/examples/tutorials/images/tumble" + at = getParameter("pause") + pause = if (at != null) Integer.valueOf(at).intValue() else 1900 + at = getParameter("offset") + offset = if (at != null) Integer.valueOf(at).intValue() else 0 + at = getParameter("speed") + speed = if (at != null) (1000 / Integer.valueOf(at).intValue()) else 100 + at = getParameter("nimgs"); + nimgs = if (at != null) Integer.valueOf(at).intValue() else 16 + at = getParameter("maxwidth"); + maxWidth = if (at != null) Integer.valueOf(at).intValue() else 0 + imgs = new Array[ImageIcon](nimgs) + } + + class ui extends UI with ActionListener { + /** + * Create the GUI. For thread safety, this method should + * be invoked from the event-dispatching thread. + */ + private def createGUI(): Unit = { + //Animate from right to left if offset is negative. + mywidth = getSize().width + if (offset < 0) { + off = mywidth - maxWidth; + } + + //Custom component to draw the current image + //at a particular offset. + animator = new Animator() + animator.opaque = true + animator.background = Color.white + setContentPane(animator.peer) + + //Put a "Loading Images..." label in the middle of + //the content pane. To center the label's text in + //the applet, put it in the center part of a + //BorderLayout-controlled container, and center-align + //the label's text. + val statusLabel = new Label("Loading Images...", + Swing.EmptyIcon, Alignment.Center) + animator.layout(statusLabel) = BorderPanel.Position.Center + } + + var animator: Animator = null //the applet's content pane + //Background task for loading images. + worker = new SwingWorker[Array[ImageIcon], Void]() { + override def doInBackground(): Array[ImageIcon] = { + val innerImgs: Array[ImageIcon] = new Array[ImageIcon](nimgs) + for (i <- 0 until nimgs) { + innerImgs(i) = loadImage(i + 1) + } + innerImgs; + } + + override def done(): Unit = { + //Remove the "Loading images" label. + animator.clear() + loopslot = -1 + try { + imgs = get() + } catch { + case ignore: java.lang.InterruptedException => {} + case e: java.util.concurrent.ExecutionException => + val cause: Throwable = e.getCause() + val why = if (cause != null) + cause.getMessage() + else + e.getMessage() + System.err.println("Error retrieving file: " + why) + } + } + } + + //Called when this applet is loaded into the browser. + override def init(): Unit = { + loadAppletParameters() + + //Execute a job on the event-dispatching thread: + //creating this applet's GUI. + try { + SwingUtilities.invokeAndWait(new Runnable() { + def run(): Unit = { + createGUI(); + } + }); + } catch { + case e: Exception => + System.err.println("createGUI didn't successfully complete") + } + + //Set up timer to drive animation events. + timer = new Timer(speed, this); + timer.setInitialDelay(pause); + timer.start(); + + //Start loading the images in the background. + worker.execute(); + + } + + override def start(): Unit = { + if (worker.isDone() && (nimgs > 1)) { + timer.restart + } + } + + override def stop(): Unit = { + timer.stop + } + + //The component that actually presents the GUI. + class Animator extends BorderPanel { + + protected def paintComponent(g: Graphics): Unit = { + super.paintComponent(g.asInstanceOf[Graphics2D]); + + if (worker.isDone() && + (loopslot > -1) && (loopslot < nimgs)) { + if (imgs != null && imgs(loopslot) != null) { + imgs(loopslot).paintIcon(peer, g, off, 0); + } + } + } + + def clear(): Unit = { + removeAll() + } + + } + + //Handle timer event. Update the loopslot (frame number) and the + //offset. If it's the last frame, restart the timer to get a long + //pause between loops. + def actionPerformed(e: ActionEvent): Unit = { + //If still loading, can't animate. + if (worker.isDone()) { + loopslot += 1 + + if (loopslot >= nimgs) { + loopslot = 0 + off += offset + + if (off < 0) { + off = mywidth - maxWidth + } else if (off + maxWidth > mywidth) { + off = 0; + } + } + animator.repaint() + if (loopslot == nimgs - 1) { + timer.restart() + } + } + } + } + + /** + * Load the image for the specified frame of animation. Since + * this runs as an applet, we use getResourceAsStream for + * efficiency and so it'll work in older versions of Java Plug-in. + */ + def loadImage(imageNum: Int): ImageIcon = { + val path = dir + "/T" + imageNum + ".gif" + val MAX_IMAGE_SIZE = 2400 //Change this to the size of + //your biggest image, in bytes. + var count = 0 + val imgStream = new BufferedInputStream(this.getClass().getResourceAsStream(path)) + if (imgStream != null) { + val buf = new Array[Byte](MAX_IMAGE_SIZE) + var ex = false + try { + count = imgStream.read(buf); + imgStream.close(); + } catch { + case ioe: java.io.IOException => + System.err.println("Couldn't read stream from file: " + path) + count = -1 + } + if (count <= 0) { + System.err.println("Empty file: " + path); + null + } else + new ImageIcon(Toolkit.getDefaultToolkit().createImage(buf)); + } else { + System.err.println("Couldn't find file: " + path); + null + } + } + + override def getAppletInfo(): String = { + "Title: TumbleItem v1.2, 23 Jul 1997\n" + + "Author: James Gosling\n" + + "A simple Item class to play an image loop." + } + + override def getParameterInfo(): Array[Array[String]] = { + val info = new Array[Array[String]](6) + info(0) = Array("img", "string", "the directory containing the images to loop") + info(1) = Array("pause", "int", "pause between complete loops; default is 3900") + info(2) = Array("offset", "int", "offset of each image to simulate left (-) or " + + "right (+) motion; default is 0 (no motion)") + info(3) = Array("speed", "int", "the speed at which the frames are looped; " + + "default is 100") + info(4) = Array("nimgs", "int", "the number of images to be looped; default is 16") + info(5) = Array("maxwidth", "int", "the maximum width of any image in the loop; " + + "default is 0") + info + } + +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala new file mode 100644 index 00000000..f62bdcfb --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package scala.swing.examples.tutorials.components; + +import java.io.File; +import javax.swing.ImageIcon; + +/* Utils.scala is used by FileChooserDemo2.java. */ +class Utils { + val jpeg = "jpeg" + val jpg = "jpg" + val gif = "gif" + val tiff = "tiff" + val tif = "tif" + val png = "png" + + /* + * Get the extension of a file. + */ + def getExtension(f: File): Option[String] = { + val s = f.getName(); + val i = s.lastIndexOf('.'); + + if (i > 0 && i < s.length() - 1) { + Some(s.substring(i + 1).toLowerCase()) + } else None + } + + /** Returns an ImageIcon, or null if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { + val imgURL: java.net.URL = getClass().getResource(path) + if (imgURL != null) { + Some(new ImageIcon(imgURL)) + } else { + System.err.println("Couldn't find file: " + path) + None + } + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala new file mode 100644 index 00000000..721496e3 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.concurrency + +import scala.swing._ +import scala.swing.event.ButtonClicked +import javax.swing.SwingWorker +import java.util.Random + +/* + * Tutorial: Tasks that Have Interim Results + * http://http://docs.oracle.com/javase/tutorial/uiswing/concurrency/interim.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java + */ +class Flipper extends Frame { + var flipTask: FlipTask = null + title = "Flipper" + + val headsText = new TextField(20) { + editable = false + horizontalAlignment = Alignment.Right + border = Swing.BeveledBorder(Swing.Lowered) + } + val totalText = new TextField(20) { + editable = false + horizontalAlignment = Alignment.Right + border = Swing.BeveledBorder(Swing.Lowered) + } + val devText = new TextField(20) { + editable = false + horizontalAlignment = Alignment.Right + border = Swing.BeveledBorder(Swing.Lowered) + } + val startButton = new Button("Start") + val stopButton = new Button("Stop") { + enabled = false + } + val panel = new GridBagPanel() { + val c = new Constraints() + c.insets = new Insets(3, 10, 3, 10) + layout(headsText) = c + layout(totalText) = c + layout(devText) = c + layout(startButton) = c + layout(stopButton) = c + } + + contents = panel + pack() + visible = true + + class FlipPair(val heads: Long, val total: Long) {} + + class FlipTask extends SwingWorker[Unit, FlipPair] { + override def doInBackground(): Unit = { + var heads: Long = 0 + var total: Long = 0 + val random: Random = new Random() + while (!isCancelled()) { + total += 1 + if (random.nextBoolean()) { + heads += 1 + } + publish(new FlipPair(heads, total)) + } + } + + override def process(pairs: java.util.List[FlipPair]): Unit = { + val pair: FlipPair = pairs.get(pairs.size - 1); + headsText.text = pair.heads.toInt.toString + totalText.text = pair.total.toInt.toString + val dt = (pair.heads.toDouble) / (pair.total.toDouble) - 0.5 + devText.text = f"$dt%.10g" + } + } + + listenTo(startButton) + listenTo(stopButton) + reactions += { + case ButtonClicked(`startButton`) => + startButton.enabled = false + stopButton.enabled = true + flipTask = new FlipTask() + flipTask.execute() + case ButtonClicked(`stopButton`) => + startButton.enabled = true + stopButton.enabled = false + flipTask.cancel(true) + flipTask = null + } + + override def closeOperation(): Unit = { + sys.exit(0) + } +} + +object Flipper { + //The standard main method. + def main(args: Array[String]): Unit = { + //Schedule a job for the event dispatch thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + new Flipper() + } + }); + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala new file mode 100644 index 00000000..e9cc3f15 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.misc + +import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.Dimension +import java.awt.event.{ActionEvent, ActionListener, KeyEvent} +import java.net.URL +import javax.swing.{ ImageIcon, JToolBar } + +/* + * Tutorials: How to Use Actions + * http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html + * + * The graphics in this application require a download of the Java Look and Feel Graphics + * Repository from Oracle. + * http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-client-419417.html#7520-jlf-1.0-oth-JPR + * Accept the user agreement from the site, unzip, and place the jar file contents in your classpath. + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/ActionDemoProject/src/misc/ActionDemo.java + * + * ActionDemo.scala requires the Java Look and Feel jar file jlfgr-1_0.jar. + */ +class ActionDemo extends BorderPanel { + //Create a scrolled text area. + val textArea = new TextArea(5, 30) { + editable = false + } + val scrollPane = new ScrollPane(textArea) + preferredSize = new Dimension(450, 150) + + layout(scrollPane) = BorderPanel.Position.Center + + //Create the actions shared by the toolbar and menu. + val leftAction = new LeftAction() + class LeftAction extends Action("Go left") with ActionListener { + override def apply(): Unit = {} + icon = ActionDemo.createNavigationIcon("Back24") + mnemonic = new Integer(KeyEvent.VK_L) + peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the left button.") + // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) + override def actionPerformed(e: ActionEvent): Unit = { + displayResult("Action for first button/menu item", e); + } + } + val middleAction = new Action("Do something") with ActionListener { + override def apply(): Unit = {} + icon = ActionDemo.createNavigationIcon("Up24") + mnemonic = new Integer(KeyEvent.VK_M) + peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the middle button.") + // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) + override def actionPerformed(e: ActionEvent): Unit = { + displayResult("Action for second button/menu item", e); + } + } + val rightAction = new Action("Go right") with ActionListener { + override def apply(): Unit = {} + icon = ActionDemo.createNavigationIcon("Forward24") + mnemonic = new Integer(KeyEvent.VK_R) + peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the right button.") + // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) + override def actionPerformed(e: ActionEvent): Unit = { + displayResult("Action for third button/menu item", e); + } + } + + def displayResult(actionDescription: String, e: ActionEvent): Unit = { + val newline = "\n" + val s: String = "Action event detected: " + + actionDescription + + newline + + " Event source: " + e.getSource() + + newline; + textArea.append(s); + } + + def createMenuBar(): MenuBar = { + //Create the menu bar. + val menuBar = new MenuBar() + + //Create the first menu. + val mainMenu = new Menu("Menu") + val actions = new Array[Action](3) + actions(0) = leftAction + actions(1) = middleAction + actions(2) = rightAction + for (i <- 0 until actions.length) { + mainMenu.contents += new MenuItem(actions(i)) { + icon = Swing.EmptyIcon + } + } + + //Set up the menu bar. + menuBar.contents += mainMenu + menuBar.contents += createAbleMenu() + menuBar + } + + def createToolBar(): Unit = { + val toolBar = new ToolBar() + //first button + val button1 = new Button(leftAction) { + if (icon != null) text = "" // an icon-only button + } + val button2 = new Button(middleAction) { + if (icon != null) text = "" // an icon-only button + } + val button3 = new Button(rightAction) { + if (icon != null) text = "" // an icon-only button + } + toolBar.contents += button1 + toolBar.contents += button2 + toolBar.contents += button3 + layout(toolBar) = BorderPanel.Position.North + } + + def createAbleMenu(): Menu = { + val ableMenu = new Menu("Action State") + val cmi1 = new CheckMenuItem("First action enabled") { selected = true } + val cmi2 = new CheckMenuItem("Second action enabled") { selected = true } + val cmi3 = new CheckMenuItem("Third action enabled") { selected = true } + + ableMenu.contents += cmi1 + ableMenu.contents += cmi2 + ableMenu.contents += cmi3 + listenTo(cmi1) + listenTo(cmi2) + listenTo(cmi3) + reactions += { + case ButtonClicked(`cmi1`) => leftAction.enabled = cmi1.selected + case ButtonClicked(`cmi2`) => middleAction.enabled = cmi2.selected + case ButtonClicked(`cmi3`) => rightAction.enabled = cmi3.selected + } + ableMenu + } + +} + +object ActionDemo { + /** Returns an ImageIcon, or null if the path was invalid. */ + def createNavigationIcon(imageName: String): ImageIcon = { + val imgLocation = "/toolbarButtonGraphics/navigation/" + imageName + ".gif" + val imageURL: URL = getClass().getResource(imgLocation) + + if (imageURL == null) { + System.err.println("Resource not found: " + + imgLocation) + return null + } else { + return new ImageIcon(imageURL) + } + } + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + def createAndShowGUI(): Unit = { + val frame = new Frame() { + title = "ActionDemo" + //Create and set up the content pane. + val demo = new ActionDemo() + demo.opaque = true //content panes must be opaque + menuBar = demo.createMenuBar() + demo.createToolBar() + contents = demo + // Display the window + pack() + visible = true + override def closeOperation() = { + sys.exit(0) + } + } + } + + def main(args: Array[String]): Unit = { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }) + } +} + +class ToolBar extends scala.swing.Component with SequentialContainer.Wrapper { + override lazy val peer: JToolBar = new JToolBar with SuperMixin +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala new file mode 100644 index 00000000..37fc1572 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.misc + +import scala.swing._ + +/* + * Tutorial: How to Use the Focus System + * http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/FocusConceptsDemoProject/src/misc/FocusConceptsDemo.java + * + * FocusConceptsDemo.scala requires no other files. + * + * When running the demo, try the following: + * 1. If necessary, click the window to give it the focus. + * 2. Move the focus from component to component using the Tab key. + * 3. You will notice that when the focus moves into the text area, it stays in the text area. + * 4. Move the focus out of the text area using Control-Tab. + * 5. Move the focus in the opposite direction using Shift-Tab. + * 6. Move the focus out of the text area in the opposite direction using Control-Shift-Tab. + */ +class FocusConceptsDemo extends BorderPanel { + val b1 = new Button("Button") + val b2 = new Button("Button") + val b3 = new Button("Button") + val b4 = new Button("Button") + + val buttonPanel = new GridPanel(1, 1) { + contents += b1 + contents += b2 + contents += b3 + contents += b4 + } + + val text1 = new TextArea("TextArea", 15, 40) + val textAreaPanel = new BorderPanel() { + layout(text1) = BorderPanel.Position.Center + } + + val t1 = new TextField("TextField") + val t2 = new TextField("TextField") + val t3 = new TextField("TextField") + val t4 = new TextField("TextField") + val textFieldPanel = new GridPanel(1,1) { + contents += t1 + contents += t2 + contents += t3 + contents += t4 + } + + layout(buttonPanel) = BorderPanel.Position.North + layout(textAreaPanel) = BorderPanel.Position.Center + layout(textFieldPanel) = BorderPanel.Position.South + border = Swing.EmptyBorder(20, 20, 20, 20) +} + +object FocusConceptsDemo { + def main(args: Array[String]): Unit = { + + /* Use an appropriate Look and Feel */ + try { + //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch { + case ex: javax.swing.UnsupportedLookAndFeelException => + ex.printStackTrace() + case ex: IllegalAccessException => + ex.printStackTrace() + case ex: InstantiationException => + ex.printStackTrace() + case ex: ClassNotFoundException => + ex.printStackTrace() + } + /* Turn off metal's use of bold fonts */ + javax.swing.UIManager.put("swing.boldMetal", false); + + + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + def run(): Unit = { + createAndShowGUI() + } + }); + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + private def createAndShowGUI(): Unit = { + //Create and set up the window. + val frame = new Frame() { + title = "FocusConceptsDemo" + override def closeOperation(): Unit = { + sys.exit(0) + } + } + + //Create and set up the content pane. + val newContentPane = new FocusConceptsDemo() + newContentPane.opaque = true //content panes must be opaque + frame.contents = newContentPane + + //Display the window. + frame.pack() + frame.visible = true + } +} \ No newline at end of file From a6e73e37f407ca34243fd4ed5ead3690d955a6ae Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 24 Sep 2014 16:43:35 +1000 Subject: [PATCH 02/36] Compile examples in the Travis build. The subproject containing the examples (added in 8db44f35a0) is not aggregated under the root project, and as such is not part of `sbt compile`. This commit adds the task `examples/compile` to the SBT command line in the Travis CI build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c7ab0d72..0511f96e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: scala script: - - sbt ++$TRAVIS_SCALA_VERSION clean update compile test + - sbt ++$TRAVIS_SCALA_VERSION clean update compile test examples/compile scala: - 2.11.1 From a74866b174e29e047638a5a438c7abf442ecbc1e Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 13:26:33 -0700 Subject: [PATCH 03/36] SimpleSwingApplication extended by companion objects. --- .../tutorials/components/BorderDemo.scala | 32 +---- .../tutorials/components/ButtonDemo.scala | 36 ++---- .../tutorials/components/ButtonHtmlDemo.scala | 32 +---- .../tutorials/components/CheckboxDemo.scala | 36 +----- .../components/ColorChooserDemo.scala | 39 +----- .../tutorials/components/ComboBoxDemo.scala | 37 +----- .../tutorials/components/ComboBoxDemo2.scala | 37 +----- .../components/CustomComboBoxDemo.scala | 37 +----- .../tutorials/components/DialogDemo.scala | 38 +----- .../components/FormattedTextFieldDemo.scala | 40 ++---- .../tutorials/components/FrameDemo.scala | 39 ++---- .../tutorials/components/FrameDemo2.scala | 119 ++++++++---------- .../tutorials/components/HtmlDemo.scala | 37 +----- .../tutorials/components/IconDemoApp.scala | 26 +--- .../tutorials/components/LabelDemo.scala | 39 ++---- .../tutorials/components/ListDemo.scala | 37 +----- .../components/ListDialogRunner.scala | 94 +++++--------- .../tutorials/components/MenuDemo.scala | 75 ++++------- .../tutorials/components/MenuGlueDemo.scala | 76 ++++------- .../tutorials/components/MenuLookDemo.scala | 38 ++---- .../tutorials/components/PasswordDemo.scala | 35 +----- .../tutorials/components/PopupMenuDemo.scala | 28 +---- .../components/RadioButtonDemo.scala | 35 +----- .../tutorials/components/ScrollDemo.scala | 35 +----- .../tutorials/components/ScrollDemo2.scala | 34 +---- .../components/SimpleTableDemo.scala | 34 +---- .../components/SimpleTableSelectionDemo.scala | 34 +---- .../tutorials/components/SliderDemo.scala | 41 ++---- .../tutorials/components/SliderDemo2.scala | 39 ++---- .../tutorials/components/SplitPaneDemo.scala | 35 +----- .../tutorials/components/SplitPaneDemo2.scala | 32 +---- .../components/SplitPaneDividerDemo.scala | 35 +----- .../tutorials/components/TabbedPaneDemo.scala | 37 +----- .../tutorials/components/TableDemo.scala | 34 +---- .../components/TableFTFEditDemo.scala | 34 +---- .../tutorials/components/TablePrintDemo.scala | 34 +---- .../components/TableSelectionDemo.scala | 36 +----- .../components/TextComponentDemo.scala | 32 +---- .../tutorials/components/TextDemo.scala | 34 +---- .../components/TextSamplerDemo.scala | 25 +--- .../tutorials/components/TopLevelDemo.scala | 27 +--- .../tutorials/concurrency/Flipper.scala | 21 +--- .../examples/tutorials/misc/ActionDemo.scala | 43 ++----- .../tutorials/misc/FocusConceptsDemo.scala | 89 +++++-------- 44 files changed, 368 insertions(+), 1439 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala index fd2ad3d3..ba1a310a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -284,7 +284,7 @@ class BorderDemo extends GridPanel(1, 0) { } -object BorderDemo { +object BorderDemo extends SimpleSwingApplication { def createImageIcon(path: String, description: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -295,30 +295,10 @@ object BorderDemo { null } } - - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "BorderDemo" - //Create and set up the content pane. - val newContentPane = new BorderDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) + + def top = new MainFrame() { + title = "BorderDemo" + //Create and set up the content pane. + contents = new BorderDemo(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala index 25c65337..1b3fe089 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala @@ -107,34 +107,12 @@ class ButtonDemo extends FlowPanel { } -object ButtonDemo { - - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ButtonDemo" - //Create and set up the content pane. - val newContentPane = new ButtonDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - - javax.swing.SwingUtilities.invokeLater(new Runnable() { - - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) +object ButtonDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "ButtonDemo" + javax.swing.UIManager.put("swing.boldMetal", false) + //Create and set up the content pane. + contents = new ButtonDemo(); } + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala index 86c0a717..f3961ac7 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -114,32 +114,10 @@ class ButtonHtmlDemo extends FlowPanel { } -object ButtonHtmlDemo { - - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ButtonHtmlDemo" - //Create and set up the content pane. - val newContentPane = new ButtonHtmlDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - - def run(): Unit = { - createAndShowGUI() - } - }) +object ButtonHtmlDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "ButtonHtmlDemo" + //Create and set up the content pane. + contents = new ButtonHtmlDemo(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index baf9dd73..8b855e8c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -157,7 +157,7 @@ class CheckboxDemo extends BorderPanel { } } -object CheckboxDemo { +object CheckboxDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -167,35 +167,9 @@ object CheckboxDemo { null } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "CheckboxDemo" - //Create and set up the content pane. - val newContentPane = new CheckboxDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "CheckboxDemo" + //Create and set up the content pane. + contents = new CheckboxDemo(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala index 36f18246..267d3e7f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala @@ -66,41 +66,14 @@ class ColorChooserDemo extends BorderPanel { } } - layout(bannerPanel) = BorderPanel.Position.Center layout(tcc) = BorderPanel.Position.South } -object ColorChooserDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ColorChooserDemo" - //Create and set up the content pane. - val newContentPane = new ColorChooserDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } +object ColorChooserDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "ColorChooserDemo" + //Create and set up the content pane. + contents = new ColorChooserDemo(); } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) - } -} \ No newline at end of file +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index 1cb4efd0..04d2912d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -83,7 +83,7 @@ class ComboBoxDemo extends BorderPanel { } } -object ComboBoxDemo { +object ComboBoxDemo extends SimpleSwingApplication { val birdString = "Bird" val catString = "Cat" val dogString = "Dog" @@ -99,36 +99,9 @@ object ComboBoxDemo { null } } - - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ComboBoxDemo" - //Create and set up the content pane. - val newContentPane = new ComboBoxDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + val top = new MainFrame() { + title = "ComboBoxDemo" + //Create and set up the content pane. + contents = new ComboBoxDemo(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala index 2f96dfde..c7b72b54 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -122,37 +122,10 @@ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { } } -object ComboBoxDemo2 { - - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ComboBoxDemo2" - //Create and set up the content pane. - val newContentPane = new ComboBoxDemo2(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) +object ComboBoxDemo2 extends SimpleSwingApplication { + def top = new MainFrame() { + title = "ComboBoxDemo2" + //Create and set up the content pane. + contents = new ComboBoxDemo2(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index 59cdf9d5..2aeda5f9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -117,7 +117,7 @@ class CustomComboBoxDemo extends BorderPanel { } } -object CustomComboBoxDemo { +object CustomComboBoxDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { @@ -128,36 +128,11 @@ object CustomComboBoxDemo { null } } - - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "CustomComboBoxDemo" - //Create and set up the content pane. - val newContentPane = new CustomComboBoxDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } + + def top = new MainFrame() { + title = "CustomComboBoxDemo" + //Create and set up the content pane. + contents = new CustomComboBoxDemo(); } - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) - } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index f013492a..4ebe3991 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -482,7 +482,7 @@ class DialogDemo(val frame: Frame) extends BorderPanel { } -object DialogDemo { +object DialogDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -493,37 +493,9 @@ object DialogDemo { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame = new Frame() { - title = "DialogDemo" - - //Create and set up the content pane. - val contentPane: DialogDemo = new DialogDemo(this) - contentPane.opaque = true - contents = contentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "DialogDemo" + //Create and set up the content pane. + contents = new DialogDemo(this); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala index 1870efed..74c28adf 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala @@ -160,38 +160,12 @@ class FormattedTextFieldDemo extends BorderPanel { } } -object FormattedTextFieldDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame = new Frame() { - title = "FormattedTextFieldDemo" - - //Create and set up the content pane. - val contentPane: FormattedTextFieldDemo = new FormattedTextFieldDemo() - contentPane.opaque = true - contents = contentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) +object FormattedTextFieldDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "FormattedTextFieldDemo" + //Create and set up the content pane. + javax.swing.UIManager.put("swing.boldMetal", false) + contents = new FormattedTextFieldDemo(); } + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala index 87f865b7..6f62aa0f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala @@ -42,39 +42,18 @@ import java.awt.Dimension * * FrameDemo.scala requires no other files. */ -object FrameDemo { +object FrameDemo extends SimpleSwingApplication { /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. + * Create the GUI and show it. */ - def createAndShowGUI(): Unit = { - val label = new Label("") { - preferredSize = new Dimension(175, 100) + def top = new MainFrame() { + title = "FrameDemo" + val emptylabel = new Label("") { + preferredSize = new Dimension(175, 100) } - //Create and set up the window. - val frame = new Frame() { - title = "FrameDemo" - contents = new BorderPanel() { - layout(label) = BorderPanel.Position.Center - } - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } + //Create and set up the content pane. + contents = new BorderPanel() { + layout(emptylabel) = BorderPanel.Position.Center } } - - //The standard main method. - def main(args: Array[String]): Unit = { - //Schedule a job for the event dispatch thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }); - } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index cad461d9..ac98a97e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -77,41 +77,49 @@ class FrameDemo2 { //Create a new MyFrame object and show it. def showNewWindow(): Unit = { - val frame = new MyFrame() + val frame: Option[Frame] = if (noDecorations) None else Some(new MyFrame()) + //Take care of the no window decorations case. //NOTE: Unless you really need the functionality //provided by JFrame, you would usually use a //Window or JWindow instead of an undecorated JFrame. - if (noDecorations) { - frame.peer.setUndecorated(true); - } + + //Undecorated frames are not supported by scala swing. Setting the Frame's + //JFrame peer to be undecorated causes Swing to throw a java.awt.IllegalComponentStateException + //with the message "The frame is displayable." + // + //if (noDecorations) { + // frame.peer.setUndecorated(true); + //} //Set window location. - if (lastLocation != null) { - //Move the window over and down 40 pixels. - lastLocation.translate(40, 40); - if ((lastLocation.x > maxX) || (lastLocation.y > maxY)) { - lastLocation.setLocation(0, 0); + if (frame.isDefined) { + val f = frame.get + if (lastLocation != null) { + //Move the window over and down 40 pixels. + lastLocation.translate(40, 40); + if ((lastLocation.x > maxX) || (lastLocation.y > maxY)) { + lastLocation.setLocation(0, 0); + } + f.location = lastLocation + } else { + lastLocation = f.location } - frame.location = lastLocation - } else { - lastLocation = frame.location - } - //Calling setIconImage sets the icon displayed when the window - //is minimized. Most window systems (or look and feels, if - //decorations are provided by the look and feel) also use this - //icon in the window decorations. - if (specifyIcon) { - if (createIcon) { - //create an icon from scratch - frame.iconImage = FrameDemo2.createFDImage() - } else { - //get the icon from a file - frame.iconImage = FrameDemo2.getFDImage() + //Calling setIconImage sets the icon displayed when the window + //is minimized. Most window systems (or look and feels, if + //decorations are provided by the look and feel) also use this + //icon in the window decorations. + if (specifyIcon) { + if (createIcon) { + //create an icon from scratch + f.iconImage = FrameDemo2.createFDImage() + } else { + //get the icon from a file + f.iconImage = FrameDemo2.getFDImage() + } } } - } // Create the window-creation controls that go in the main window. @@ -187,7 +195,13 @@ class FrameDemo2 { JFrame.setDefaultLookAndFeelDecorated(false) case ButtonClicked(`rb3`) => noDecorations = true - JFrame.setDefaultLookAndFeelDecorated(false) + //Undecorated frames are not supported by scala swing. Setting the Frame's + //JFrame peer to be undecorated causes Swing to throw a java.awt.IllegalComponentStateException + //with the message "The frame is displayable." + // + // No need to set the default look and feel decorated property to false. + // JFrame.setDefaultLookAndFeelDecorated(false) + println("Undecorated frames are not supported by Scala Swing.") case ButtonClicked(`rb4`) => specifyIcon = false case ButtonClicked(`rb5`) => specifyIcon = true @@ -249,7 +263,7 @@ class MyFrame extends Frame { } } -object FrameDemo2 { +object FrameDemo2 extends SimpleSwingApplication { //Creates an icon-worthy Image from scratch. def createFDImage(): Image = { //Create a 16x16 pixel image. @@ -277,52 +291,29 @@ object FrameDemo2 { return null; } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Use the Java look and feel. + + val top = new Frame() { + title = "FrameDemo2" + //Use the Java look and feel. This needs to be done before the frame is created + //so the companion object FrameDemo2 cannot simply extend SimpleSwingApplcation. try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch { case e: Exception => ; } - //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); + //Create and set up the content pane. + val demo = new FrameDemo2(); + //Add components to it. + val contentPane = peer.getContentPane() - //Instantiate the controlling class. - val frame = new Frame() { - title = "FrameDemo2" - //Create and set up the content pane. - val demo = new FrameDemo2(); - //Add components to it. - val contentPane = peer.getContentPane() - override def closeOperation() = { - sys.exit(0) - } - } - frame.contentPane.add(frame.demo.createOptionControls(frame), - BorderLayout.CENTER) - frame.contentPane.add(frame.demo.createButtonPane(frame), - BorderLayout.PAGE_END) - //Display the window - frame.pack() - frame.visible = true - } - - //Start the demo. - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI(); - } - }) } + top.contentPane.add(top.demo.createOptionControls(top), + BorderLayout.CENTER) + top.contentPane.add(top.demo.createButtonPane(top), + BorderLayout.PAGE_END) + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala index 5d0066b1..6cc244ce 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala @@ -97,37 +97,10 @@ class HtmlDemo extends BoxPanel(Orientation.Horizontal) { } } -object HtmlDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "HtmlDemo" - //Create and set up the content pane. - val newContentPane = new HtmlDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - //Turn off metal's use of bold fonts - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) +object HtmlDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "HtmlDemo" + //Create and set up the content pane. + contents = new HtmlDemo(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index a697dfc3..418b7067 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -67,7 +67,7 @@ import javax.swing.{ Icon, ImageIcon, JToolBar, SwingWorker } * @date 7/25/2007 * @version 2.0 */ -class IconDemoApp extends Frame { +class IconDemoApp extends MainFrame { private val imagedir = "/scala/swing/examples/tutorials/images/" private val placeholderIcon = new MissingIcon() @@ -101,7 +101,6 @@ class IconDemoApp extends Frame { layout(buttonBar) = BorderPanel.Position.South layout(photographLabel) = BorderPanel.Position.Center } - visible = true size = new Dimension(400, 300) // this centers the frame on the screen @@ -110,10 +109,6 @@ class IconDemoApp extends Frame { // start the image loading SwingWorker in a background thread loadImages.execute() - override def closeOperation() = { - sys.exit(0) - } - /** * SwingWorker class that loads the images a background thread and calls publish * when a new one is ready to be displayed. @@ -187,7 +182,7 @@ class IconDemoApp extends Frame { } } -object IconDemoApp { +object IconDemoApp extends SimpleSwingApplication { def createImageIcon(path: String, description: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) @@ -198,20 +193,9 @@ object IconDemoApp { None } } - /** - * Main entry point to the demo. Loads the Swing elements on the "Event - * Dispatch Thread". - * - * @param args - */ - def main(args: Array[String]) { - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run() { - val app = new IconDemoApp() { - visible = true - } - } - }); + + def top = new IconDemoApp() { + title = "IconDemoApp" } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index 3d4143a4..f6c62e5e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -67,7 +67,7 @@ class LabelDemo extends GridPanel(3, 1) { contents += label3 } -object LabelDemo { +object LabelDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String, description: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -78,36 +78,11 @@ object LabelDemo { null } } - - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "LabelDemo" - //Create and set up the content pane. - val newContentPane = new LabelDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "LabelDemo" + //Create and set up the content pane. + javax.swing.UIManager.put("swing.boldMetal", false) + contents = new LabelDemo(); } + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala index c81f7c48..ac90f531 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala @@ -160,38 +160,11 @@ class ListDemo extends BorderPanel { } } } -object ListDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame: Frame = new Frame() { - title = "ListDemo" - override def closeOperation() = { - sys.exit(0) - } - } - //Create and set up the content pane. - val newContentPane = new ListDemo() { - opaque = true - } - frame.contents = newContentPane - //Display the window. - frame.pack() - frame.visible = true - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object ListDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "ListDemo" + //Create and set up the content pane. + contents = new ListDemo(); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala index b4426e99..276b4c7d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala @@ -43,44 +43,39 @@ import scala.swing.event.ButtonClicked * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java */ -object ListDialogRunner { + +class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) { val names: Array[String] = Array("Arlo", "Cosmo", "Elmo", "Hugo", "Jethro", "Laszlo", "Milo", "Nemo", "Otto", "Ringo", "Rocco", "Rollo") - var frame: Frame = null - def createUI(): BoxPanel = { - val panel = new BoxPanel(Orientation.NoOrientation) { - //Create the labels. - val intro = new Label("The chosen name:") - val nameLabel = new Label(names(1)) { - //Use a wacky font if it exists. If not, this falls - //back to a font we know exists. - font = getAFont() - } - intro.peer.setLabelFor(nameLabel.peer) + //Create the labels. + val intro = new Label("The chosen name:") + val nameLabel = new Label(names(1)) { + //Use a wacky font if it exists. If not, this falls + //back to a font we know exists. + font = getAFont() + } + intro.peer.setLabelFor(nameLabel.peer) - //Create the button. - val button = new Button("Pick a new name...") + //Create the button. + val button = new Button("Pick a new name...") - contents += intro - contents += nameLabel - contents += button + contents += intro + contents += nameLabel + contents += button - listenTo(button) - reactions += { - case ButtonClicked(`button`) => - nameLabel.text = ListDialog.showDialog( - frame, - button, - "Baby names ending in 0:", - "Name chooser", - names.asInstanceOf[Array[String]], - nameLabel.text, - "Cosmo ") - } - } - panel + listenTo(button) + reactions += { + case ButtonClicked(`button`) => + nameLabel.text = ListDialog.showDialog( + frame, + button, + "Baby names ending in 0:", + "Name chooser", + names.asInstanceOf[Array[String]], + nameLabel.text, + "Cosmo ") } def getAFont(): Font = { @@ -113,37 +108,12 @@ object ListDialogRunner { new Font("Serif", Font.ITALIC, 36) } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - frame = new Frame() { - title = "Name That Baby" - - //Create and set up the content pane. - val contentPane: BoxPanel = createUI() - contentPane.opaque = true - contents = contentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } +} - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) +object ListDialogRunner extends SimpleSwingApplication { + def top = new MainFrame() { + title = "Name That Baby" + //Create and set up the content pane. + contents = new ListDialogRunner(this); } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index 3d011799..426c92b8 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -31,7 +31,7 @@ package scala.swing.examples.tutorials.components import scala.swing._ -import scala.swing.event.{ButtonClicked, Key} +import scala.swing.event.{ ButtonClicked, Key } import java.net.URL import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } @@ -67,7 +67,7 @@ class MenuDemo extends BorderPanel { val menuItem1 = new MenuItem(new Action("A text-only menu item") { def apply() = {} accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_1, ActionEvent.ALT_MASK)) + KeyEvent.VK_1, ActionEvent.ALT_MASK)) longDescription = "This doesn't really do anything" }) { mnemonic = Key.T @@ -119,7 +119,7 @@ class MenuDemo extends BorderPanel { val menuItemS1 = new MenuItem(new Action("An item in the submenu") { def apply() = {} accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_2, ActionEvent.ALT_MASK)) + KeyEvent.VK_2, ActionEvent.ALT_MASK)) }) submenu.contents += menuItemS1 // @@ -155,15 +155,15 @@ class MenuDemo extends BorderPanel { case ButtonClicked(`menuItemS1`) => actionPerformed(menuItemS1) case ButtonClicked(`menuItemS2`) => actionPerformed(menuItemS2) // No ItemEvents in scala.swing.... -// case SelectionChanged(`menuItem1`) => itemStateChanged(menuItem1) -// case SelectionChanged(`menuItem2`) => itemStateChanged(menuItem2) -// case SelectionChanged(`menuItem3`) => itemStateChanged(menuItem3) -// case SelectionChanged(`rbMenuItem1`) => itemStateChanged(rbMenuItem1) -// case SelectionChanged(`rbMenuItem2`) => itemStateChanged(rbMenuItem2) -// case SelectionChanged(`cbMenuItem1`) => itemStateChanged(cbMenuItem1) -// case SelectionChanged(`cbMenuItem2`) => itemStateChanged(cbMenuItem2) -// case SelectionChanged(`menuItemS1`) => itemStateChanged(menuItemS1) -// case SelectionChanged(`menuItemS2`) => itemStateChanged(menuItemS2) + // case SelectionChanged(`menuItem1`) => itemStateChanged(menuItem1) + // case SelectionChanged(`menuItem2`) => itemStateChanged(menuItem2) + // case SelectionChanged(`menuItem3`) => itemStateChanged(menuItem3) + // case SelectionChanged(`rbMenuItem1`) => itemStateChanged(rbMenuItem1) + // case SelectionChanged(`rbMenuItem2`) => itemStateChanged(rbMenuItem2) + // case SelectionChanged(`cbMenuItem1`) => itemStateChanged(cbMenuItem1) + // case SelectionChanged(`cbMenuItem2`) => itemStateChanged(cbMenuItem2) + // case SelectionChanged(`menuItemS1`) => itemStateChanged(menuItemS1) + // case SelectionChanged(`menuItemS2`) => itemStateChanged(menuItemS2) } menuBar } @@ -171,13 +171,13 @@ class MenuDemo extends BorderPanel { def actionPerformed(source: MenuItem) { val newline = "\n" val s = "Action event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")"; - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() + newline + + " Event source: " + source.text + + " (an instance of " + getClassName(source) + ")"; + output.append(s + newline); + output.caret.position = output.peer.getDocument().getLength() } - + def itemStateChanged(source: MenuItem) { val newline = "\n" val s = "Item event detected." + @@ -199,7 +199,7 @@ class MenuDemo extends BorderPanel { } } -object MenuDemo { +object MenuDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -209,38 +209,11 @@ object MenuDemo { null } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame: Frame = new Frame() { - title = "MenuDemo" - override def closeOperation() = { - sys.exit(0) - } - } + def top = new MainFrame() { + title = "MenuDemo" //Create and set up the content pane. - val newContentPane = new MenuDemo() { - opaque = true - } - frame.menuBar = newContentPane.createMenuBar - frame.contents = newContentPane - - //Display the window. - frame.pack() - frame.visible = true - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) + val newContentPane = new MenuDemo(); + menuBar = newContentPane.createMenuBar + contents = newContentPane } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala index 086ccf19..4ee19b6a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala @@ -46,57 +46,31 @@ import scala.swing._ * @author kwalrath */ /* MenuGlueDemo.scala requires no other files. */ -class MenuGlueDemo { - def createMenuBar(): MenuBar = { - val menuBar = new MenuBar(); - menuBar.contents += createMenu("Menu 1") - menuBar.contents += createMenu("Menu 2") - menuBar.contents += Swing.HGlue - menuBar.contents += createMenu("Menu 3") - menuBar; - } - - def createMenu(title: String): Menu = { - val m = new Menu(title); - m.contents += new MenuItem("Menu item #1 in " + title) - m.contents += new MenuItem("Menu item #2 in " + title) - m.contents += new MenuItem("Menu item #3 in " + title) - m; - } +class MenuGlueDemo extends MainFrame { + def createMenuBar(): MenuBar = { + val menuBar = new MenuBar(); + menuBar.contents += createMenu("Menu 1") + menuBar.contents += createMenu("Menu 2") + menuBar.contents += Swing.HGlue + menuBar.contents += createMenu("Menu 3") + menuBar; + } + + def createMenu(title: String): Menu = { + val m = new Menu(title); + m.contents += new MenuItem("Menu item #1 in " + title) + m.contents += new MenuItem("Menu item #2 in " + title) + m.contents += new MenuItem("Menu item #3 in " + title) + m; + } } -object MenuGlueDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame = new Frame() { - title = "MenuGlueDemo" - //Create and set up the content pane. - val demo = new MenuGlueDemo(); - // Display the window - contents = new FlowPanel() { - contents += demo.createMenuBar() - } - size = new Dimension(300, 100) - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } +object MenuGlueDemo extends SimpleSwingApplication { + def top = new MenuGlueDemo() { + title = "MenuGlueDemo" + contents = new FlowPanel() { + contents += createMenuBar() } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI(); - } - }) - } -} \ No newline at end of file + size = new Dimension(300, 100) + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala index 59819d34..78db1712 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -74,7 +74,7 @@ class MenuLookDemo extends BorderPanel { } menu.contents += menuItem1 // - val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon: ImageIcon = MenuLookDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") val menuItem2 = new MenuItem("Both text and icon") { icon = icon mnemonic = Key.B @@ -169,7 +169,7 @@ class MenuLookDemo extends BorderPanel { } } -object MenuLookDemo { +object MenuLookDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -179,38 +179,14 @@ object MenuLookDemo { null } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame: Frame = new Frame() { - title = "MenuLookDemo" - override def closeOperation() = { - sys.exit(0) - } - } + + def top = new MainFrame() { + title = "MenuLookDemo" //Create and set up the content pane. val newContentPane = new MenuLookDemo() { opaque = true } - frame.menuBar = newContentPane.createMenuBar - frame.contents = newContentPane - - //Display the window. - frame.pack() - frame.visible = true - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) + menuBar = newContentPane.createMenuBar + contents = newContentPane } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala index 9aafcc38..7e6a41fc 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala @@ -63,7 +63,7 @@ class PasswordDemo(val controllingFrame: Frame) extends FlowPanel { } } -object PasswordDemo { +object PasswordDemo extends SimpleSwingApplication { /** * Checks the passed-in array against the correct password. * After this method returns, you should invoke eraseArray @@ -88,34 +88,9 @@ object PasswordDemo { correctPassword.update(i, '0') isCorrect; } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event dispatch thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "PasswordDemo" - //Create and set up the content pane. - val newContentPane = new PasswordDemo(this) - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - //The standard main method. - def main(args: Array[String]): Unit = { - //Schedule a job for the event dispatch thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }); + def top = new MainFrame() { + title = "PasswordDemo" + //Create and set up the content pane. + contents = new PasswordDemo(this) } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala index bd6cf81b..7d8eb58b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -77,7 +77,7 @@ class PopupMenuDemo extends BorderPanel { } menu.contents += menuItem1 // - val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon: ImageIcon = PopupMenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") val menuItem2 = new MenuItem("Both text and icon") { icon = icon mnemonic = Key.B @@ -235,7 +235,7 @@ class PopupMenuDemo extends BorderPanel { } } -object PopupMenuDemo { +object PopupMenuDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -250,35 +250,19 @@ object PopupMenuDemo { * this method should be invoked from the * event-dispatching thread. */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame: Frame = new Frame() { + def top = new MainFrame() { title = "PopupMenuDemo" - override def closeOperation() = { - sys.exit(0) - } - } //Create and set up the content pane. val demo = new PopupMenuDemo() { opaque = true } - frame.menuBar = demo.createMenuBar - frame.contents = demo + menuBar = demo.createMenuBar + contents = demo //Create and set up the popup menu. demo.createPopupMenu() //Display the window. - frame.size = new Dimension(450, 260) - frame.visible = true + size = new Dimension(450, 260) } - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) - } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index abd73006..a4ff5c9c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -121,7 +121,7 @@ class RadioButtonDemo extends BorderPanel { } } -object RadioButtonDemo { +object RadioButtonDemo extends SimpleSwingApplication { val birdString = "Bird" val catString = "Cat" val dogString = "Dog" @@ -137,35 +137,8 @@ object RadioButtonDemo { null } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "RadioButtonDemo" - //Create and set up the content pane. - val newContentPane = new RadioButtonDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "RadioButtonDemo" + contents = new RadioButtonDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala index 2ba84fc2..1c8004d8 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -117,7 +117,7 @@ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { } } -object ScrollDemo { +object ScrollDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -129,35 +129,8 @@ object ScrollDemo { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ScrollDemo" - //Create and set up the content pane. - val newContentPane = new ScrollDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "ScrollDemo" + contents = new ScrollDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala index fb348421..1544816c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala @@ -132,35 +132,9 @@ class ScrollDemo2 extends BorderPanel { } -object ScrollDemo2 { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ScrollDemo2" - //Create and set up the content pane. - val newContentPane = new ScrollDemo2(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object ScrollDemo2 extends SimpleSwingApplication { + def top = new MainFrame() { + title = "ScrollDemo2" + contents = new ScrollDemo2() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala index 8ba4c41b..b507d397 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala @@ -90,35 +90,9 @@ class SimpleTableDemo extends GridPanel(1, 0) { } } -object SimpleTableDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "SimpleTableDemo" - //Create and set up the content pane. - val newContentPane = new SimpleTableDemo() - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object SimpleTableDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "SimpleTableDemo" + contents = new SimpleTableDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala index 6e1a1004..2e8bbdc5 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala @@ -142,35 +142,9 @@ class SimpleTableSelectionDemo extends GridPanel(1, 0) { } } -object SimpleTableSelectionDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "SimpleTableSelectionDemo" - //Create and set up the content pane. - val newContentPane = new SimpleTableSelectionDemo() - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object SimpleTableSelectionDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "SimpleTableSelectionDemo" + contents = new SimpleTableSelectionDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index 280acdf7..ad525fae 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -119,7 +119,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act case WindowDeiconified(`window`) => startAnimation() } - + startAnimation() def startAnimation(): Unit = { @@ -169,7 +169,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act } } -object SliderDemo { +object SliderDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -181,36 +181,13 @@ object SliderDemo { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "SliderDemo" - //Create and set up the content pane. - val newContentPane = new SliderDemo(this); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "SliderDemo" + javax.swing.UIManager.put("swing.boldMetal", false) + //Create and set up the content pane. + contents = new SliderDemo(this); } + + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 153753df..72410c7c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -168,7 +168,7 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { } } -object SliderDemo2 { +object SliderDemo2 extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -180,36 +180,13 @@ object SliderDemo2 { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "SliderDemo2" - //Create and set up the content pane. - val newContentPane = new SliderDemo2(this); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "SliderDemo2" + javax.swing.UIManager.put("swing.boldMetal", false) + //Create and set up the content pane. + contents = new SliderDemo2(this); } + + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index b489c05a..a733e522 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -98,7 +98,7 @@ class SplitPaneDemo extends FlowPanel { } } -object SplitPaneDemo { +object SplitPaneDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -110,36 +110,9 @@ object SplitPaneDemo { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "SplitPaneDemo" - //Create and set up the content pane. - val newContentPane = new SplitPaneDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "SplitPaneDemo" + contents = new SplitPaneDemo() } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala index 2bf9c822..25121660 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -43,7 +43,7 @@ import javax.swing.ImageIcon * Source code reference: * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemo2Project/src/components/SplitPaneDemo2.java */ -class SplitPaneDemo2 extends Frame { +class SplitPaneDemo2 extends MainFrame { title = "SplitPaneDemo2" //Create an instance of SplitPaneDemo. @@ -92,7 +92,7 @@ class SplitPaneDemo2 extends Frame { } -object SplitPaneDemo2 { +object SplitPaneDemo2 extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -104,32 +104,6 @@ object SplitPaneDemo2 { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new SplitPaneDemo2() { - title = "SplitPaneDemo2" - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) - } + val top = new SplitPaneDemo2() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index ada1f202..fda22138 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -86,7 +86,7 @@ class SplitPaneDividerDemo extends BorderPanel { } } -object SplitPaneDividerDemo { +object SplitPaneDividerDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -98,36 +98,9 @@ object SplitPaneDividerDemo { } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "SplitPaneDividerDemo" - //Create and set up the content pane. - val newContentPane = new SplitPaneDividerDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "SplitPaneDividerDemo" + contents = new SplitPaneDividerDemo() } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala index 0c08b2ed..e2a4cccc 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala @@ -79,7 +79,7 @@ class TabbedPaneDemo extends GridPanel(1, 1) { } } -object TabbedPaneDemo { +object TabbedPaneDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -90,37 +90,10 @@ object TabbedPaneDemo { null } } - - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "TabbedPaneDemo" - //Create and set up the content pane. - val newContentPane = new TabbedPaneDemo(); - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) + + def top = new MainFrame() { + title = "TabbedPaneDemo" + contents = new TabbedPaneDemo() } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala index a7d7d12a..ce3f5250 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala @@ -126,35 +126,9 @@ class TableDemo extends GridPanel(1, 0) { } } -object TableDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "TableDemo" - //Create and set up the content pane. - val newContentPane = new TableDemo() - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object TableDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "TableDemo" + contents = new TableDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala index 8cc1ea92..78576637 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala @@ -135,35 +135,9 @@ class TableFTFEditDemo extends GridPanel(1, 0) { } } -object TableFTFEditDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "TableFTFEditDemo" - //Create and set up the content pane. - val newContentPane = new TableFTFEditDemo() - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object TableFTFEditDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "TableFTFEditDemo" + contents = new TableFTFEditDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala index 6367615a..c0e73f4d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala @@ -147,35 +147,9 @@ class TablePrintDemo extends BoxPanel(Orientation.Vertical) { } -object TablePrintDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "TablePrintDemo" - //Create and set up the content pane. - val newContentPane = new TablePrintDemo() - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object TablePrintDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "TablePrintDemo" + contents = new TablePrintDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala index 11132226..fbe1e623 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala @@ -239,35 +239,9 @@ class TableSelectionDemo extends BoxPanel(Orientation.Vertical) { } } -object TableSelectionDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "TableSelectionDemo" - //Create and set up the content pane. - val newContentPane = new TableSelectionDemo() - newContentPane.opaque = true //content panes must be opaque - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) +object TableSelectionDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "TableSelectionDemo" + contents = new TableSelectionDemo() } -} +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index 7bff6fc6..fc2bf786 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -54,7 +54,7 @@ import javax.swing.undo.UndoManager * TextComponentDemo.scala requires one additional file: * DocumentSizeFilter.scala */ -class TextComponentDemo extends Frame { +class TextComponentDemo extends MainFrame { private val MaxCharacters = 300 private val newline = "\n" title = "TextComponentDemo" @@ -392,31 +392,9 @@ class TextComponentDemo extends Frame { } -object TextComponentDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event dispatch thread. - */ - def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame = new TextComponentDemo(); - - //Display the window. - frame.pack(); - frame.visible = true - } - - //The standard main method. - def main(args: Array[String]): Unit = { - //Schedule a job for the event dispatch thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - //Turn off metal's use of bold fonts - UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }); +object TextComponentDemo extends SimpleSwingApplication { + def top = new TextComponentDemo() { + javax.swing.UIManager.put("swing.boldMetal", false) } + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala index 92f9d579..5ebf981b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala @@ -74,35 +74,9 @@ class TextDemo extends GridBagPanel { } } -object TextDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event dispatch thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "TextDemo" - //Create and set up the content pane. - val newContentPane = new TextDemo() - contents = newContentPane - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - - //The standard main method. - def main(args: Array[String]): Unit = { - //Schedule a job for the event dispatch thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }); +object TextDemo extends SimpleSwingApplication { + def top = new MainFrame() { + title = "TextDemo" + contents = new TextDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala index a09ba427..ae758fc8 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -50,11 +50,10 @@ import scala.swing.event._ * /scala/swing/examples/tutorials/images/Pig.gif * /scala/swing/examples/tutorials/images/sound.gif */ -object TextSamplerDemo { +object TextSamplerDemo extends SimpleSwingApplication { val newline = "\n" - def createAndShowGUI(): Unit = { - val top = new Frame() { + def top = new MainFrame() { title = "TextSamplerDemo" private val textFieldString = "TextField" @@ -223,16 +222,8 @@ object TextSamplerDemo { layout(leftPane) = BorderPanel.Position.West layout(rightPane) = BorderPanel.Position.East } - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } } - } - def addStylesToDocument(doc: javax.swing.text.StyledDocument, button: Button): Unit = { val `def` = StyleContext.getDefaultStyleContext.getStyle(StyleContext.DEFAULT_STYLE) val regular = doc.addStyle("regular", `def`) @@ -303,20 +294,8 @@ object TextSamplerDemo { } img } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - javax.swing.UIManager.put("swing.boldMetal", false) - createAndShowGUI() - } - }) - } } - class TextPane() extends TextComponent { override lazy val peer: javax.swing.JTextPane = new javax.swing.JTextPane() with SuperMixin def styledDocument: javax.swing.text.StyledDocument = peer.getStyledDocument() diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala index 15cfe0fb..c4495920 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala @@ -41,14 +41,8 @@ import scala.swing._ * * TopLevelDemo.scala requires no other files. */ -object TopLevelDemo { - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - private def createAndShowGUI(): Unit = { - val frame = new Frame() { +object TopLevelDemo extends SimpleSwingApplication { + def top = new MainFrame() { title = "TopLevelDemo" //Create the menu bar. Make it have a green background. @@ -70,22 +64,5 @@ object TopLevelDemo { contents = new BorderPanel { layout(yellowlabel) = BorderPanel.Position.Center } - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } } - } - - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) - } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala index 721496e3..a4b1352f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala @@ -42,7 +42,7 @@ import java.util.Random * Source code reference: * http://docs.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java */ -class Flipper extends Frame { +class Flipper extends MainFrame { var flipTask: FlipTask = null title = "Flipper" @@ -76,8 +76,6 @@ class Flipper extends Frame { } contents = panel - pack() - visible = true class FlipPair(val heads: Long, val total: Long) {} @@ -118,21 +116,8 @@ class Flipper extends Frame { flipTask.cancel(true) flipTask = null } - - override def closeOperation(): Unit = { - sys.exit(0) - } } -object Flipper { - //The standard main method. - def main(args: Array[String]): Unit = { - //Schedule a job for the event dispatch thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - new Flipper() - } - }); - } +object Flipper extends SimpleSwingApplication { + def top = new Flipper() } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala index e9cc3f15..34f43014 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala @@ -33,7 +33,7 @@ package scala.swing.examples.tutorials.misc import scala.swing._ import scala.swing.event.ButtonClicked import java.awt.Dimension -import java.awt.event.{ActionEvent, ActionListener, KeyEvent} +import java.awt.event.{ ActionEvent, ActionListener, KeyEvent } import java.net.URL import javax.swing.{ ImageIcon, JToolBar } @@ -125,7 +125,7 @@ class ActionDemo extends BorderPanel { menuBar.contents += createAbleMenu() menuBar } - + def createToolBar(): Unit = { val toolBar = new ToolBar() //first button @@ -166,7 +166,7 @@ class ActionDemo extends BorderPanel { } -object ActionDemo { +object ActionDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ def createNavigationIcon(imageName: String): ImageIcon = { val imgLocation = "/toolbarButtonGraphics/navigation/" + imageName + ".gif" @@ -180,37 +180,14 @@ object ActionDemo { return new ImageIcon(imageURL) } } - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - def createAndShowGUI(): Unit = { - val frame = new Frame() { - title = "ActionDemo" - //Create and set up the content pane. - val demo = new ActionDemo() - demo.opaque = true //content panes must be opaque - menuBar = demo.createMenuBar() - demo.createToolBar() - contents = demo - // Display the window - pack() - visible = true - override def closeOperation() = { - sys.exit(0) - } - } - } - def main(args: Array[String]): Unit = { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }) + def top = new MainFrame() { + title = "ActionDemo" + //Create and set up the content pane. + val demo = new ActionDemo() + menuBar = demo.createMenuBar() + demo.createToolBar() + contents = demo } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala index 37fc1572..987ae7ef 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala @@ -54,88 +54,59 @@ class FocusConceptsDemo extends BorderPanel { val b2 = new Button("Button") val b3 = new Button("Button") val b4 = new Button("Button") - + val buttonPanel = new GridPanel(1, 1) { contents += b1 contents += b2 contents += b3 contents += b4 } - + val text1 = new TextArea("TextArea", 15, 40) val textAreaPanel = new BorderPanel() { layout(text1) = BorderPanel.Position.Center } - + val t1 = new TextField("TextField") val t2 = new TextField("TextField") val t3 = new TextField("TextField") val t4 = new TextField("TextField") - val textFieldPanel = new GridPanel(1,1) { + val textFieldPanel = new GridPanel(1, 1) { contents += t1 contents += t2 contents += t3 contents += t4 } - + layout(buttonPanel) = BorderPanel.Position.North layout(textAreaPanel) = BorderPanel.Position.Center layout(textFieldPanel) = BorderPanel.Position.South border = Swing.EmptyBorder(20, 20, 20, 20) } -object FocusConceptsDemo { - def main(args: Array[String]): Unit = { - - /* Use an appropriate Look and Feel */ - try { - //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); - //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); - javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); - } catch { - case ex: javax.swing.UnsupportedLookAndFeelException => - ex.printStackTrace() - case ex: IllegalAccessException => - ex.printStackTrace() - case ex: InstantiationException => - ex.printStackTrace() - case ex: ClassNotFoundException => - ex.printStackTrace() - } - /* Turn off metal's use of bold fonts */ - javax.swing.UIManager.put("swing.boldMetal", false); - - - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - createAndShowGUI() - } - }); - } - - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - private def createAndShowGUI(): Unit = { - //Create and set up the window. - val frame = new Frame() { - title = "FocusConceptsDemo" - override def closeOperation(): Unit = { - sys.exit(0) - } - } - - //Create and set up the content pane. - val newContentPane = new FocusConceptsDemo() - newContentPane.opaque = true //content panes must be opaque - frame.contents = newContentPane - - //Display the window. - frame.pack() - frame.visible = true - } +object FocusConceptsDemo extends SimpleSwingApplication { + + /* Use an appropriate Look and Feel */ + try { + //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch { + case ex: javax.swing.UnsupportedLookAndFeelException => + ex.printStackTrace() + case ex: IllegalAccessException => + ex.printStackTrace() + case ex: InstantiationException => + ex.printStackTrace() + case ex: ClassNotFoundException => + ex.printStackTrace() + } + /* Turn off metal's use of bold fonts */ + javax.swing.UIManager.put("swing.boldMetal", false); + //Create and set up the window. + def top = new MainFrame() { + title = "FocusConceptsDemo" + contents = new FocusConceptsDemo() + } + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file From e4c86d337ace25d37420ba7c0ef3eee5645dca13 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 15:43:33 -0700 Subject: [PATCH 04/36] Make lazy val references to the MainFrame variable in most of the tutorials. --- .../swing/examples/tutorials/components/BorderDemo.scala | 2 +- .../swing/examples/tutorials/components/ButtonDemo.scala | 2 +- .../examples/tutorials/components/ButtonHtmlDemo.scala | 2 +- .../swing/examples/tutorials/components/CheckboxDemo.scala | 2 +- .../examples/tutorials/components/ColorChooserDemo.scala | 2 +- .../swing/examples/tutorials/components/ComboBoxDemo.scala | 2 +- .../swing/examples/tutorials/components/ComboBoxDemo2.scala | 2 +- .../examples/tutorials/components/CustomComboBoxDemo.scala | 2 +- .../swing/examples/tutorials/components/DialogDemo.scala | 2 +- .../examples/tutorials/components/FileChooserDemo.scala | 2 +- .../tutorials/components/FormattedTextFieldDemo.scala | 2 +- .../swing/examples/tutorials/components/FrameDemo.scala | 2 +- .../swing/examples/tutorials/components/FrameDemo2.scala | 2 +- .../swing/examples/tutorials/components/HtmlDemo.scala | 2 +- .../swing/examples/tutorials/components/IconDemoApp.scala | 2 +- .../swing/examples/tutorials/components/LabelDemo.scala | 2 +- .../swing/examples/tutorials/components/ListDemo.scala | 2 +- .../examples/tutorials/components/ListDialogRunner.scala | 2 +- .../swing/examples/tutorials/components/MenuDemo.scala | 2 +- .../swing/examples/tutorials/components/MenuGlueDemo.scala | 2 +- .../swing/examples/tutorials/components/MenuLookDemo.scala | 2 +- .../swing/examples/tutorials/components/PasswordDemo.scala | 2 +- .../swing/examples/tutorials/components/PopupMenuDemo.scala | 6 ++---- .../examples/tutorials/components/RadioButtonDemo.scala | 2 +- .../swing/examples/tutorials/components/ScrollDemo.scala | 2 +- .../swing/examples/tutorials/components/ScrollDemo2.scala | 2 +- .../examples/tutorials/components/SimpleTableDemo.scala | 2 +- .../tutorials/components/SimpleTableSelectionDemo.scala | 2 +- .../swing/examples/tutorials/components/SliderDemo.scala | 2 +- .../swing/examples/tutorials/components/SliderDemo2.scala | 2 +- .../swing/examples/tutorials/components/SplitPaneDemo.scala | 2 +- .../examples/tutorials/components/SplitPaneDemo2.scala | 2 +- .../tutorials/components/SplitPaneDividerDemo.scala | 2 +- .../examples/tutorials/components/TabbedPaneDemo.scala | 2 +- .../swing/examples/tutorials/components/TableDemo.scala | 2 +- .../examples/tutorials/components/TableFTFEditDemo.scala | 2 +- .../examples/tutorials/components/TablePrintDemo.scala | 2 +- .../examples/tutorials/components/TableSelectionDemo.scala | 2 +- .../examples/tutorials/components/TextComponentDemo.scala | 2 +- .../swing/examples/tutorials/components/TextDemo.scala | 2 +- .../examples/tutorials/components/TextSamplerDemo.scala | 2 +- .../swing/examples/tutorials/components/TopLevelDemo.scala | 2 +- .../swing/examples/tutorials/concurrency/Flipper.scala | 2 +- .../scala/swing/examples/tutorials/misc/ActionDemo.scala | 2 +- .../swing/examples/tutorials/misc/FocusConceptsDemo.scala | 2 +- 45 files changed, 46 insertions(+), 48 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala index ba1a310a..fb60119b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -296,7 +296,7 @@ object BorderDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "BorderDemo" //Create and set up the content pane. contents = new BorderDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala index 1b3fe089..32a8c9e9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala @@ -108,7 +108,7 @@ class ButtonDemo extends FlowPanel { } object ButtonDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ButtonDemo" javax.swing.UIManager.put("swing.boldMetal", false) //Create and set up the content pane. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala index f3961ac7..2a817f46 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -115,7 +115,7 @@ class ButtonHtmlDemo extends FlowPanel { } object ButtonHtmlDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ButtonHtmlDemo" //Create and set up the content pane. contents = new ButtonHtmlDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index 8b855e8c..03c88e19 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -167,7 +167,7 @@ object CheckboxDemo extends SimpleSwingApplication { null } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "CheckboxDemo" //Create and set up the content pane. contents = new CheckboxDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala index 267d3e7f..59ef6ffd 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala @@ -71,7 +71,7 @@ class ColorChooserDemo extends BorderPanel { } object ColorChooserDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ColorChooserDemo" //Create and set up the content pane. contents = new ColorChooserDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index 04d2912d..65e392b6 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -99,7 +99,7 @@ object ComboBoxDemo extends SimpleSwingApplication { null } } - val top = new MainFrame() { + lazy val top = new MainFrame() { title = "ComboBoxDemo" //Create and set up the content pane. contents = new ComboBoxDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala index c7b72b54..7d9c099e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -123,7 +123,7 @@ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { } object ComboBoxDemo2 extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ComboBoxDemo2" //Create and set up the content pane. contents = new ComboBoxDemo2(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index 2aeda5f9..dec2d5d4 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -129,7 +129,7 @@ object CustomComboBoxDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "CustomComboBoxDemo" //Create and set up the content pane. contents = new CustomComboBoxDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index 4ebe3991..bf764fd6 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -493,7 +493,7 @@ object DialogDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "DialogDemo" //Create and set up the content pane. contents = new DialogDemo(this); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala index 40d6e0e5..d8eeeb41 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala @@ -90,7 +90,7 @@ object FileChooserDemo extends SimpleSwingApplication { contents += saveButton } - def top = new MainFrame { + lazy val top = new MainFrame { title = "FileChooserDemo" val bp = new BorderPanel { layout(buttonPanel) = BorderPanel.Position.North diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala index 74c28adf..c7374338 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala @@ -161,7 +161,7 @@ class FormattedTextFieldDemo extends BorderPanel { } object FormattedTextFieldDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "FormattedTextFieldDemo" //Create and set up the content pane. javax.swing.UIManager.put("swing.boldMetal", false) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala index 6f62aa0f..6f6f79ff 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala @@ -46,7 +46,7 @@ object FrameDemo extends SimpleSwingApplication { /** * Create the GUI and show it. */ - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "FrameDemo" val emptylabel = new Label("") { preferredSize = new Dimension(175, 100) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index ac98a97e..48a1da49 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -292,7 +292,7 @@ object FrameDemo2 extends SimpleSwingApplication { } } - val top = new Frame() { + lazy val top = new Frame() { title = "FrameDemo2" //Use the Java look and feel. This needs to be done before the frame is created //so the companion object FrameDemo2 cannot simply extend SimpleSwingApplcation. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala index 6cc244ce..12e3aa3c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala @@ -98,7 +98,7 @@ class HtmlDemo extends BoxPanel(Orientation.Horizontal) { } object HtmlDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "HtmlDemo" //Create and set up the content pane. contents = new HtmlDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index 418b7067..6b60e09a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -194,7 +194,7 @@ object IconDemoApp extends SimpleSwingApplication { } } - def top = new IconDemoApp() { + lazy val top = new IconDemoApp() { title = "IconDemoApp" } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index f6c62e5e..c8770ad3 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -78,7 +78,7 @@ object LabelDemo extends SimpleSwingApplication { null } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "LabelDemo" //Create and set up the content pane. javax.swing.UIManager.put("swing.boldMetal", false) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala index ac90f531..14f38cdb 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala @@ -162,7 +162,7 @@ class ListDemo extends BorderPanel { } object ListDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ListDemo" //Create and set up the content pane. contents = new ListDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala index 276b4c7d..d5b86bc0 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala @@ -111,7 +111,7 @@ class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) } object ListDialogRunner extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "Name That Baby" //Create and set up the content pane. contents = new ListDialogRunner(this); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index 426c92b8..1841c562 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -209,7 +209,7 @@ object MenuDemo extends SimpleSwingApplication { null } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "MenuDemo" //Create and set up the content pane. val newContentPane = new MenuDemo(); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala index 4ee19b6a..227a7f51 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala @@ -66,7 +66,7 @@ class MenuGlueDemo extends MainFrame { } object MenuGlueDemo extends SimpleSwingApplication { - def top = new MenuGlueDemo() { + lazy val top = new MenuGlueDemo() { title = "MenuGlueDemo" contents = new FlowPanel() { contents += createMenuBar() diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala index 78db1712..f6b8798f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -180,7 +180,7 @@ object MenuLookDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "MenuLookDemo" //Create and set up the content pane. val newContentPane = new MenuLookDemo() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala index 7e6a41fc..139b0d03 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala @@ -88,7 +88,7 @@ object PasswordDemo extends SimpleSwingApplication { correctPassword.update(i, '0') isCorrect; } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "PasswordDemo" //Create and set up the content pane. contents = new PasswordDemo(this) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala index 7d8eb58b..cc9d13ed 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -246,11 +246,9 @@ object PopupMenuDemo extends SimpleSwingApplication { } } /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. + * Create the GUI and show it. */ - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "PopupMenuDemo" //Create and set up the content pane. val demo = new PopupMenuDemo() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index a4ff5c9c..dc75a274 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -137,7 +137,7 @@ object RadioButtonDemo extends SimpleSwingApplication { null } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "RadioButtonDemo" contents = new RadioButtonDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala index 1c8004d8..f8d61f31 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -129,7 +129,7 @@ object ScrollDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ScrollDemo" contents = new ScrollDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala index 1544816c..e01f4f0c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala @@ -133,7 +133,7 @@ class ScrollDemo2 extends BorderPanel { } object ScrollDemo2 extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ScrollDemo2" contents = new ScrollDemo2() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala index b507d397..ca262085 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala @@ -91,7 +91,7 @@ class SimpleTableDemo extends GridPanel(1, 0) { } object SimpleTableDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "SimpleTableDemo" contents = new SimpleTableDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala index 2e8bbdc5..5fa5cdb6 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala @@ -143,7 +143,7 @@ class SimpleTableSelectionDemo extends GridPanel(1, 0) { } object SimpleTableSelectionDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "SimpleTableSelectionDemo" contents = new SimpleTableSelectionDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index ad525fae..0bf618d9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -181,7 +181,7 @@ object SliderDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "SliderDemo" javax.swing.UIManager.put("swing.boldMetal", false) //Create and set up the content pane. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 72410c7c..39bd0c31 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -180,7 +180,7 @@ object SliderDemo2 extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "SliderDemo2" javax.swing.UIManager.put("swing.boldMetal", false) //Create and set up the content pane. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index a733e522..35886011 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -110,7 +110,7 @@ object SplitPaneDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "SplitPaneDemo" contents = new SplitPaneDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala index 25121660..02fd467d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -104,6 +104,6 @@ object SplitPaneDemo2 extends SimpleSwingApplication { } } - val top = new SplitPaneDemo2() + lazy val top = new SplitPaneDemo2() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index fda22138..04e01b41 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -98,7 +98,7 @@ object SplitPaneDividerDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "SplitPaneDividerDemo" contents = new SplitPaneDividerDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala index e2a4cccc..8118d419 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala @@ -91,7 +91,7 @@ object TabbedPaneDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TabbedPaneDemo" contents = new TabbedPaneDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala index ce3f5250..40153862 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala @@ -127,7 +127,7 @@ class TableDemo extends GridPanel(1, 0) { } object TableDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TableDemo" contents = new TableDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala index 78576637..3f7de552 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala @@ -136,7 +136,7 @@ class TableFTFEditDemo extends GridPanel(1, 0) { } object TableFTFEditDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TableFTFEditDemo" contents = new TableFTFEditDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala index c0e73f4d..50e0ce4f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala @@ -148,7 +148,7 @@ class TablePrintDemo extends BoxPanel(Orientation.Vertical) { } object TablePrintDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TablePrintDemo" contents = new TablePrintDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala index fbe1e623..901732f1 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala @@ -240,7 +240,7 @@ class TableSelectionDemo extends BoxPanel(Orientation.Vertical) { } object TableSelectionDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TableSelectionDemo" contents = new TableSelectionDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index fc2bf786..bc8ffce1 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -393,7 +393,7 @@ class TextComponentDemo extends MainFrame { } object TextComponentDemo extends SimpleSwingApplication { - def top = new TextComponentDemo() { + lazy val top = new TextComponentDemo() { javax.swing.UIManager.put("swing.boldMetal", false) } javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala index 5ebf981b..cb8b21a0 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala @@ -75,7 +75,7 @@ class TextDemo extends GridBagPanel { } object TextDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TextDemo" contents = new TextDemo() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala index ae758fc8..70695c10 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -53,7 +53,7 @@ import scala.swing.event._ object TextSamplerDemo extends SimpleSwingApplication { val newline = "\n" - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TextSamplerDemo" private val textFieldString = "TextField" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala index c4495920..9650acc2 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala @@ -42,7 +42,7 @@ import scala.swing._ * TopLevelDemo.scala requires no other files. */ object TopLevelDemo extends SimpleSwingApplication { - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "TopLevelDemo" //Create the menu bar. Make it have a green background. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala index a4b1352f..6a3327ae 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala @@ -119,5 +119,5 @@ class Flipper extends MainFrame { } object Flipper extends SimpleSwingApplication { - def top = new Flipper() + lazy val top = new Flipper() } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala index 34f43014..239af132 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala @@ -181,7 +181,7 @@ object ActionDemo extends SimpleSwingApplication { } } - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "ActionDemo" //Create and set up the content pane. val demo = new ActionDemo() diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala index 987ae7ef..8e061b5a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala @@ -104,7 +104,7 @@ object FocusConceptsDemo extends SimpleSwingApplication { /* Turn off metal's use of bold fonts */ javax.swing.UIManager.put("swing.boldMetal", false); //Create and set up the window. - def top = new MainFrame() { + lazy val top = new MainFrame() { title = "FocusConceptsDemo" contents = new FocusConceptsDemo() } From 3323bcf56a03aa2b3dbafb84b08e2b192e4528d4 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 15:46:46 -0700 Subject: [PATCH 05/36] Remove the spurious comment that the process method is never called by the SwingWorker in IconDemoApp.scala. It is getting called now. --- .../scala/swing/examples/tutorials/components/IconDemoApp.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index 6b60e09a..66e54365 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -144,7 +144,6 @@ class IconDemoApp extends MainFrame { */ override def process(chunks: java.util.List[ThumbnailAction]): Unit = { println("process") - // Problem: process never gets called. val it: java.util.Iterator[ThumbnailAction] = chunks.iterator() while (it.hasNext()) { val thumbAction = it.next() From 390b51545864edaacb962a31e37abef2fb1313ff Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 16:14:06 -0700 Subject: [PATCH 06/36] Remove unneeded references to the peer's minimumSize, preferredSize, and size. --- .../tutorials/components/SizeDisplayer.scala | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala index 3e7f7cce..70388180 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala @@ -15,15 +15,12 @@ class SizeDisplayer(text: String, icon: Icon) extends Label(text, icon, Alignmen //lots of unnecessary Dimensions and Rectangles. private var textSizeR = new Rectangle() private var textSizeD = new Dimension() - var userPreferredSize: Dimension = null - var userMinimumSize: Dimension = null - var userMaximumSize: Dimension = null + private var userPreferredSize: Dimension = null + private var userMinimumSize: Dimension = null + private var userMaximumSize: Dimension = null def paintComponent(g: Graphics): Unit = { val g2d = g.create().asInstanceOf[Graphics2D] //copy g - val minSize: Dimension = peer.getMinimumSize(); - val prefSize: Dimension = peer.getPreferredSize(); - val size: Dimension = peer.getSize(); var prefX = 0 var prefY = 0; @@ -52,17 +49,17 @@ class SizeDisplayer(text: String, icon: Icon) extends Label(text, icon, Alignmen } //Draw the preferred size rectangle. - prefX = (size.width - prefSize.width) / 2 - prefY = (size.height - prefSize.height) / 2 + prefX = (size.width - preferredSize.width) / 2 + prefY = (size.height - preferredSize.height) / 2 g2d.setColor(Color.RED) - g2d.drawRect(prefX, prefY, prefSize.width - 1, prefSize.height - 1) + g2d.drawRect(prefX, prefY, preferredSize.width - 1, preferredSize.height - 1) //Draw the minimum size rectangle. - if (minSize.width != prefSize.width || minSize.height != prefSize.height) { - val minX = (size.width - minSize.width) / 2 - val minY = (size.height - minSize.height) / 2 + if (minimumSize.width != preferredSize.width || minimumSize.height != preferredSize.height) { + val minX = (size.width - minimumSize.width) / 2 + val minY = (size.height - minimumSize.height) / 2 g2d.setColor(Color.CYAN) - g2d.drawRect(minX, minY, minSize.width - 1, minSize.height - 1) + g2d.drawRect(minX, minY, minimumSize.width - 1, minimumSize.height - 1) } //Draw the text. From cdce672ec8938c5c6ec483b10bd01b4a79f08c09 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 16:15:40 -0700 Subject: [PATCH 07/36] Get rid of deprecated procedure syntax instances. --- .../swing/examples/tutorials/components/MenuDemo.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index 1841c562..73f18162 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -168,7 +168,7 @@ class MenuDemo extends BorderPanel { menuBar } - def actionPerformed(source: MenuItem) { + def actionPerformed(source: MenuItem): Unit = { val newline = "\n" val s = "Action event detected." + newline + @@ -178,7 +178,7 @@ class MenuDemo extends BorderPanel { output.caret.position = output.peer.getDocument().getLength() } - def itemStateChanged(source: MenuItem) { + def itemStateChanged(source: MenuItem): Unit = { val newline = "\n" val s = "Item event detected." + newline + @@ -192,7 +192,7 @@ class MenuDemo extends BorderPanel { } // Returns just the class name -- no package info. - def getClassName(o: AnyRef) { + def getClassName(o: AnyRef): String = { val classString = o.getClass().getName() val dotIndex = classString.lastIndexOf(".") classString.substring(dotIndex + 1) From 9d138a44606c31500762b9207ff72c8e499f12e5 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 16:16:26 -0700 Subject: [PATCH 08/36] Factor out common code that is getting icons from the same directory. --- .../tutorials/components/RadioButtonDemo.scala | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index dc75a274..6c47c10f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -109,15 +109,19 @@ class RadioButtonDemo extends BorderPanel { reactions += { case ButtonClicked(`birdButton`) => - picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.birdString + ".gif") + picture.icon = getPictureIcon(RadioButtonDemo.birdString) case ButtonClicked(`catButton`) => - picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.catString + ".gif") + picture.icon = getPictureIcon(RadioButtonDemo.catString) case ButtonClicked(`dogButton`) => - picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.dogString + ".gif") + picture.icon = getPictureIcon(RadioButtonDemo.dogString) case ButtonClicked(`rabbitButton`) => - picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.rabbitString + ".gif") + picture.icon = getPictureIcon(RadioButtonDemo.rabbitString) case ButtonClicked(`pigButton`) => - picture.icon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + RadioButtonDemo.pigString + ".gif") + picture.icon = getPictureIcon(RadioButtonDemo.pigString) + } + + def getPictureIcon(gifName: String): ImageIcon = { + RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + gifName + ".gif") } } From 5288a4ed0c332b0cd3fe348245f9a572ebd74b12 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 19:35:55 -0700 Subject: [PATCH 09/36] Fix the caret event handling. Fix undo and redo menu items using javax swing custom actions attatched to menu item peers. --- .../components/TextComponentDemo.scala | 93 ++++++++++++------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index bc8ffce1..ed8cffa2 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -30,15 +30,14 @@ */ package scala.swing.examples.tutorials.components - import scala.collection.mutable.HashMap import scala.swing._ import scala.swing.event.CaretUpdate import java.awt.{ Color, Dimension, Event, Insets } import java.awt.event.KeyEvent import javax.swing.{ InputMap, KeyStroke, SwingUtilities, UIManager } -import javax.swing.event.{DocumentEvent, DocumentListener, UndoableEditEvent, UndoableEditListener} -import javax.swing.text.{AbstractDocument, BadLocationException, DefaultEditorKit, Document, SimpleAttributeSet, StyleConstants, StyledDocument, StyledEditorKit} +import javax.swing.event.{ DocumentEvent, DocumentListener, UndoableEditEvent, UndoableEditListener } +import javax.swing.text.{ AbstractDocument, BadLocationException, DefaultEditorKit, Document, SimpleAttributeSet, StyleConstants, StyledDocument, StyledEditorKit } import javax.swing.undo.UndoManager /* @@ -62,7 +61,7 @@ class TextComponentDemo extends MainFrame { //Create the text pane and configure it. val textPane: TextPane = new TextPane() - textPane.peer.setCaretPosition(0) + textPane.caret.position = 0 textPane.peer.setMargin(new Insets(5, 5, 5, 5)) val styledDoc: StyledDocument = textPane.styledDocument val doc: AbstractDocument = styledDoc.asInstanceOf[AbstractDocument] @@ -70,7 +69,7 @@ class TextComponentDemo extends MainFrame { val scrollPane = new ScrollPane(textPane) scrollPane.preferredSize = new Dimension(200, 200) - + val undoAction = new UndoAction() val redoAction = new RedoAction() @@ -109,10 +108,10 @@ class TextComponentDemo extends MainFrame { //Put the initial text into the text pane. initDocument() - textPane.peer.setCaretPosition(0) + textPane.caret.position = 0 //Start watching for undoable edits and caret changes. - listenTo(this) + listenTo(textPane.caret) doc.addUndoableEditListener(new MyUndoableEditListener()) reactions += { case CaretUpdate(textPane) => @@ -121,9 +120,9 @@ class TextComponentDemo extends MainFrame { doc.addDocumentListener(new MyDocumentListener()) override def closeOperation() = { - System.exit(0) + sys.exit(0) } - + class MyUndoableEditListener extends UndoableEditListener { def undoableEditHappened(e: UndoableEditEvent) { undo.addEdit(e.getEdit()) @@ -131,7 +130,7 @@ class TextComponentDemo extends MainFrame { redoAction.updateRedoState() } } - + class MyDocumentListener extends DocumentListener { def insertUpdate(e: DocumentEvent): Unit = { displayEditInfo(e) @@ -146,10 +145,10 @@ class TextComponentDemo extends MainFrame { val document: Document = e.getDocument() val changeLength = e.getLength() changeLog.append(e.getType.toString() + ":" + - changeLength + " character" + - (if (changeLength == 1) {". "} else {"s. "}) + - " Text length = " + document.getLength() + - "." + newline) + changeLength + " character" + + (if (changeLength == 1) { ". " } else { "s. " }) + + " Text length = " + document.getLength() + + "." + newline) } } @@ -172,10 +171,15 @@ class TextComponentDemo extends MainFrame { def createEditMenu(): Menu = { val menu: Menu = new Menu("Edit") { // undoAction = new UndoAction() - contents += new MenuItem(undoAction) + val undoMenuItem = new MenuItem("Undo") + undoMenuItem.peer.setAction(undoAction) + contents += undoMenuItem //redoAction = new RedoAction() - contents += new MenuItem(redoAction) + val redoMenuItem = new MenuItem("Redo") + redoMenuItem.peer.setAction(redoAction) + contents += redoMenuItem contents += new Separator() + // //These actions come from the default editor kit. //Get the ones we want and stick them in the menu. // cut-to-clipboard @@ -203,7 +207,7 @@ class TextComponentDemo extends MainFrame { } menu } - + def createStyleMenu(): Menu = { val menu: Menu = new Menu("Style") { val boldAction = new StyledEditorKit.BoldAction() @@ -308,7 +312,7 @@ class TextComponentDemo extends MainFrame { StyleConstants.setForeground(attrs(5), Color.red) attrs } - + //The following two methods allow us to find an //action provided by the editor kit by its name. def createActionTable(textComponent: TextComponent): HashMap[String, javax.swing.Action] = { @@ -323,38 +327,57 @@ class TextComponentDemo extends MainFrame { def getActionByName(name: String): Option[javax.swing.Action] = { actions.get(name) } - + // javax.swing.event.UndoableEditEvent // - class UndoAction extends Action("Undo") { + class UndoAction extends javax.swing.AbstractAction("Undo") { + setEnabled(false) - def apply = {} - - enabled = false + def actionPerformed(e: java.awt.event.ActionEvent): Unit = { + try { + undo.undo(); + } catch { + case ex: javax.swing.undo.CannotUndoException => + println("Unable to undo: " + ex) + ex.printStackTrace() + } + updateUndoState() + redoAction.updateRedoState() + } def updateUndoState(): Unit = { if (undo.canUndo()) { - enabled = true - // putValue(Action.NAME, undo.getUndoPresentationName()) + setEnabled(true) + putValue(javax.swing.Action.NAME, undo.getUndoPresentationName()) } else { - enabled = false - // putValue(Action.NAME, "Undo") + setEnabled(false) + putValue(javax.swing.Action.NAME, "Undo") } } } - class RedoAction extends Action("Redo") { - enabled = false - - def apply = {} + class RedoAction extends javax.swing.AbstractAction("Redo") { + setEnabled(false) + def actionPerformed(e: java.awt.event.ActionEvent): Unit = { + try { + undo.redo() + } catch { + case ex: javax.swing.undo.CannotUndoException => + println("Unable to undo: " + ex) + ex.printStackTrace() + } + updateRedoState(); + redoAction.updateRedoState() + } + def updateRedoState(): Unit = { if (undo.canRedo()) { - enabled = true - // putValue(Action.NAME, undo.getRedoPresentationName()) + setEnabled(true) + putValue(javax.swing.Action.NAME, undo.getRedoPresentationName()) } else { - enabled = false - // putValue(Action.NAME, "Redo") + setEnabled(false) + putValue(javax.swing.Action.NAME, "Redo") } } } From 1dc107ef683637c85158785d58661a6dc22c8e73 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 21:09:40 -0700 Subject: [PATCH 10/36] Rewrite of the undo and redo actions so that no use is made of the menu item peers or action peers. Use Swing.onEDT to place this computation on the Swing event dispatch thread. Fix the caret event handling. --- .../components/TextComponentDemo.scala | 86 ++++++++++++------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index ed8cffa2..cab22c3f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -31,8 +31,9 @@ package scala.swing.examples.tutorials.components import scala.collection.mutable.HashMap +import scala.concurrent.{ future, Future } import scala.swing._ -import scala.swing.event.CaretUpdate +import scala.swing.event.{ActionEvent, CaretUpdate} import java.awt.{ Color, Dimension, Event, Insets } import java.awt.event.KeyEvent import javax.swing.{ InputMap, KeyStroke, SwingUtilities, UIManager } @@ -119,10 +120,6 @@ class TextComponentDemo extends MainFrame { } doc.addDocumentListener(new MyDocumentListener()) - override def closeOperation() = { - sys.exit(0) - } - class MyUndoableEditListener extends UndoableEditListener { def undoableEditHappened(e: UndoableEditEvent) { undo.addEdit(e.getEdit()) @@ -170,13 +167,42 @@ class TextComponentDemo extends MainFrame { def createEditMenu(): Menu = { val menu: Menu = new Menu("Edit") { - // undoAction = new UndoAction() - val undoMenuItem = new MenuItem("Undo") - undoMenuItem.peer.setAction(undoAction) + val undoMenuItem = new MenuItem(undoAction) { + enabled = false + reactions += { + case scala.swing.event.ButtonClicked(_) => { + import scala.concurrent.ExecutionContext.Implicits._ + val fUndo: Future[Unit] = future { + Swing.onEDT { + val actionEvent = new ActionEvent(this) + undoAction.actionPerformed(actionEvent) + } + } + fUndo onComplete { + case _ => {} + } + } + } + } contents += undoMenuItem - //redoAction = new RedoAction() - val redoMenuItem = new MenuItem("Redo") - redoMenuItem.peer.setAction(redoAction) + val redoMenuItem = new MenuItem(redoAction) { + enabled = false + reactions += { + case scala.swing.event.ButtonClicked(_) => { + import scala.concurrent.ExecutionContext.Implicits._ + val fRedo: Future[Unit] = future { + Swing.onEDT { + val actionEvent: ActionEvent = new ActionEvent(this) + redoAction.actionPerformed(actionEvent) + } + } + fRedo onComplete { + case _ => {} + } + } + } + } + contents += redoMenuItem contents += new Separator() // @@ -328,12 +354,10 @@ class TextComponentDemo extends MainFrame { actions.get(name) } - // javax.swing.event.UndoableEditEvent - // - class UndoAction extends javax.swing.AbstractAction("Undo") { - setEnabled(false) - - def actionPerformed(e: java.awt.event.ActionEvent): Unit = { + class UndoAction extends Action("Undo") { + enabled = false + def apply() = {} + def actionPerformed(e: scala.swing.event.ActionEvent): Unit = { try { undo.undo(); } catch { @@ -347,19 +371,19 @@ class TextComponentDemo extends MainFrame { def updateUndoState(): Unit = { if (undo.canUndo()) { - setEnabled(true) - putValue(javax.swing.Action.NAME, undo.getUndoPresentationName()) + enabled = true + peer.putValue(javax.swing.Action.NAME, undo.getUndoPresentationName()) } else { - setEnabled(false) - putValue(javax.swing.Action.NAME, "Undo") + enabled = false + peer.putValue(javax.swing.Action.NAME, "Undo") } } } - class RedoAction extends javax.swing.AbstractAction("Redo") { - setEnabled(false) - - def actionPerformed(e: java.awt.event.ActionEvent): Unit = { + class RedoAction extends Action("Redo") { + enabled = false + def apply() = {} + def actionPerformed(e: ActionEvent): Unit = { try { undo.redo() } catch { @@ -368,16 +392,16 @@ class TextComponentDemo extends MainFrame { ex.printStackTrace() } updateRedoState(); - redoAction.updateRedoState() + undoAction.updateUndoState() } - + def updateRedoState(): Unit = { if (undo.canRedo()) { - setEnabled(true) - putValue(javax.swing.Action.NAME, undo.getRedoPresentationName()) + enabled = true + peer.putValue(javax.swing.Action.NAME, undo.getRedoPresentationName()) } else { - setEnabled(false) - putValue(javax.swing.Action.NAME, "Redo") + enabled = false + peer.putValue(javax.swing.Action.NAME, "Redo") } } } From 8135ffbffa8903d20c90683607e13f572b1ccbe1 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 21:27:38 -0700 Subject: [PATCH 11/36] Move TextPane from the end of TextSampleDemo into /scala/swing as a Swing component in its own right. Change the source code and html for the TextSampleDemo so that it refers to scala.swing components instead of swing jcomponents. --- .../tutorials/TextSamplerDemoHelp.html | 2 +- .../tutorials/components/TextSamplerDemo.scala | 11 +++-------- src/main/scala/scala/swing/TextPane.scala | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 src/main/scala/scala/swing/TextPane.scala diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html b/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html index 36571986..8f2e779f 100644 --- a/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html +++ b/examples/src/main/resources/scala/swing/examples/tutorials/TextSamplerDemoHelp.html @@ -4,7 +4,7 @@ Styled Text Sample Waving Duke icon -

This is an uneditable JEditorPane, +

This is an uneditable EditorPane, which was initialized with HTML text from a URL. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala index 70695c10..07c4316f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -131,7 +131,7 @@ object TextSamplerDemo extends SimpleSwingApplication { //Create a text area. val textArea = new TextArea( - "This is an editable JTextArea. " + + "This is an editable TextArea. " + "A text area is a \"plain\" text component, " + "which means that although it can display text " + "in any font, all of the text is in the same font.") @@ -172,7 +172,6 @@ object TextSamplerDemo extends SimpleSwingApplication { editorScrollPane.minimumSize = new java.awt.Dimension(10, 10) //Create a text pane and put it into a scrollpane. - // JTextPane has no analogue in scala.swing // val textPane:TextPane = new TextPane() val textPane: TextPane = createTextPane(button) @@ -260,7 +259,7 @@ object TextSamplerDemo extends SimpleSwingApplication { def createTextPane(button: Button): TextPane = { val initStrings: Array[String] = Array( - "This is an editable JTextPane, ", //regular + "This is an editable TextPane, ", //regular "another ", //italic "styled ", //bold "text ", //small @@ -269,7 +268,7 @@ object TextSamplerDemo extends SimpleSwingApplication { " " + newline, //button "...and embedded icons..." + newline, //regular " ", //icon - newline + "JTextPane is a subclass of JEditorPane that " + + newline + "Its peer, JTextPane, is a subclass of JEditorPane that " + "uses a StyledEditorKit and StyledDocument, and provides " + "cover methods for interacting with those objects.") val initStyles: Array[String] = Array( @@ -296,10 +295,6 @@ object TextSamplerDemo extends SimpleSwingApplication { } } -class TextPane() extends TextComponent { - override lazy val peer: javax.swing.JTextPane = new javax.swing.JTextPane() with SuperMixin - def styledDocument: javax.swing.text.StyledDocument = peer.getStyledDocument() -} diff --git a/src/main/scala/scala/swing/TextPane.scala b/src/main/scala/scala/swing/TextPane.scala new file mode 100644 index 00000000..3ffd1a89 --- /dev/null +++ b/src/main/scala/scala/swing/TextPane.scala @@ -0,0 +1,18 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ +package scala.swing + +/** + * A text component used to model styled paragraphs of text. + * + * @see javax.swing.JTextPane + */ +class TextPane() extends TextComponent { + override lazy val peer: javax.swing.JTextPane = new javax.swing.JTextPane() with SuperMixin + def styledDocument: javax.swing.text.StyledDocument = peer.getStyledDocument() +} \ No newline at end of file From 7f3f70a3c13616cfe440c5c18746016d253f614d Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 21:29:47 -0700 Subject: [PATCH 12/36] Fixed a comment in Utils that said a null is returned when instead an Option.None is returned. --- .../scala/scala/swing/examples/tutorials/components/Utils.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala index f62bdcfb..161fc754 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala @@ -55,7 +55,7 @@ class Utils { } else None } - /** Returns an ImageIcon, or null if the path was invalid. */ + /** Returns an ImageIcon option, or None if the path was invalid. */ def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: java.net.URL = getClass().getResource(path) if (imgURL != null) { From aeddf89d82a782ffcc551b2b7da77234b2cd8ab9 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 21:35:15 -0700 Subject: [PATCH 13/36] Remove scala.swing.examples.tutorials.components.Utils. It is used by FileChooserDemo2 which is not scalified yet. --- .../examples/tutorials/components/Utils.scala | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala deleted file mode 100644 index 161fc754..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/Utils.scala +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components; - -import java.io.File; -import javax.swing.ImageIcon; - -/* Utils.scala is used by FileChooserDemo2.java. */ -class Utils { - val jpeg = "jpeg" - val jpg = "jpg" - val gif = "gif" - val tiff = "tiff" - val tif = "tif" - val png = "png" - - /* - * Get the extension of a file. - */ - def getExtension(f: File): Option[String] = { - val s = f.getName(); - val i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - Some(s.substring(i + 1).toLowerCase()) - } else None - } - - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: java.net.URL = getClass().getResource(path) - if (imgURL != null) { - Some(new ImageIcon(imgURL)) - } else { - System.err.println("Couldn't find file: " + path) - None - } - } -} From 014216e1466824d1cf3fd8aaedaa9399404820c9 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 21:40:34 -0700 Subject: [PATCH 14/36] Adding the example source directory as a source path in Eclipse added more dot files that we do not want in git. --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f236bdfa..d3cdbcbb 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ build.properties /.cache /.idea /.settings +/examples/.classpath +/examples/.project # bak files produced by ./cleanup-commit *.bak @@ -42,4 +44,4 @@ qbin # Mac specific, but that is common enough a dev platform to warrant inclusion. .DS_Store -target/ \ No newline at end of file +target/ From bc4796a73542bba8100c596dff977dc31ad0f700 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 23:06:55 -0700 Subject: [PATCH 15/36] Move the ToolBar out of the tutorial code and into scala/swing. Change ActionDemo so that scala-swing events are used instead of an ActionListener. --- .../examples/tutorials/misc/ActionDemo.scala | 64 ++++++++++--------- src/main/scala/scala/swing/ToolBar.scala | 5 ++ 2 files changed, 38 insertions(+), 31 deletions(-) create mode 100644 src/main/scala/scala/swing/ToolBar.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala index 239af132..0fe7388b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala @@ -31,9 +31,9 @@ package scala.swing.examples.tutorials.misc import scala.swing._ -import scala.swing.event.ButtonClicked +import scala.swing.event.{ ActionEvent, ButtonClicked, KeyEvent } import java.awt.Dimension -import java.awt.event.{ ActionEvent, ActionListener, KeyEvent } +//import java.awt.event.{ ActionEvent, ActionListener, KeyEvent } import java.net.URL import javax.swing.{ ImageIcon, JToolBar } @@ -63,43 +63,34 @@ class ActionDemo extends BorderPanel { //Create the actions shared by the toolbar and menu. val leftAction = new LeftAction() - class LeftAction extends Action("Go left") with ActionListener { + class LeftAction extends Action("Go left") { override def apply(): Unit = {} icon = ActionDemo.createNavigationIcon("Back24") - mnemonic = new Integer(KeyEvent.VK_L) + mnemonic = new Integer(java.awt.event.KeyEvent.VK_L) peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the left button.") // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) - override def actionPerformed(e: ActionEvent): Unit = { - displayResult("Action for first button/menu item", e); - } } - val middleAction = new Action("Do something") with ActionListener { + val middleAction = new Action("Do something") { override def apply(): Unit = {} icon = ActionDemo.createNavigationIcon("Up24") - mnemonic = new Integer(KeyEvent.VK_M) + mnemonic = new Integer(java.awt.event.KeyEvent.VK_M) peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the middle button.") // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) - override def actionPerformed(e: ActionEvent): Unit = { - displayResult("Action for second button/menu item", e); - } } - val rightAction = new Action("Go right") with ActionListener { + val rightAction = new Action("Go right") { override def apply(): Unit = {} icon = ActionDemo.createNavigationIcon("Forward24") - mnemonic = new Integer(KeyEvent.VK_R) + mnemonic = new Integer(java.awt.event.KeyEvent.VK_R) peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the right button.") // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) - override def actionPerformed(e: ActionEvent): Unit = { - displayResult("Action for third button/menu item", e); - } } - - def displayResult(actionDescription: String, e: ActionEvent): Unit = { + + def displayResult(actionDescription: String, source: String): Unit = { val newline = "\n" val s: String = "Action event detected: " + actionDescription + newline + - " Event source: " + e.getSource() + + " Event source: " + source + newline; textArea.append(s); } @@ -114,12 +105,20 @@ class ActionDemo extends BorderPanel { actions(0) = leftAction actions(1) = middleAction actions(2) = rightAction - for (i <- 0 until actions.length) { - mainMenu.contents += new MenuItem(actions(i)) { - icon = Swing.EmptyIcon - } + val mi0 = new MenuItem(actions(0)) { icon = Swing.EmptyIcon } + val mi1 = new MenuItem(actions(1)) { icon = Swing.EmptyIcon } + val mi2 = new MenuItem(actions(2)) { icon = Swing.EmptyIcon } + mainMenu.contents += mi0 + mainMenu.contents += mi1 + mainMenu.contents += mi2 + listenTo(mi0) + listenTo(mi1) + listenTo(mi2) + reactions += { + case ButtonClicked(`mi0`) => displayResult("Action for first button/menu item", "Menu Item 1") + case ButtonClicked(`mi1`) => displayResult("Action for second button/menu item", "Menu Item 2") + case ButtonClicked(`mi2`) => displayResult("Action for third button/menu item", "Menu Item 3") } - //Set up the menu bar. menuBar.contents += mainMenu menuBar.contents += createAbleMenu() @@ -142,6 +141,14 @@ class ActionDemo extends BorderPanel { toolBar.contents += button2 toolBar.contents += button3 layout(toolBar) = BorderPanel.Position.North + listenTo(button1) + listenTo(button2) + listenTo(button3) + reactions += { + case ButtonClicked(`button1`) => displayResult("Action for first button/menu item", "Toolbar button 1") + case ButtonClicked(`button2`) => displayResult("Action for second button/menu item", "Toolbar button 2") + case ButtonClicked(`button3`) => displayResult("Action for third button/menu item", "Toolbar button 3") + } } def createAbleMenu(): Menu = { @@ -173,8 +180,7 @@ object ActionDemo extends SimpleSwingApplication { val imageURL: URL = getClass().getResource(imgLocation) if (imageURL == null) { - System.err.println("Resource not found: " - + imgLocation) + System.err.println("Resource not found: " + imgLocation) return null } else { return new ImageIcon(imageURL) @@ -190,7 +196,3 @@ object ActionDemo extends SimpleSwingApplication { contents = demo } } - -class ToolBar extends scala.swing.Component with SequentialContainer.Wrapper { - override lazy val peer: JToolBar = new JToolBar with SuperMixin -} \ No newline at end of file diff --git a/src/main/scala/scala/swing/ToolBar.scala b/src/main/scala/scala/swing/ToolBar.scala new file mode 100644 index 00000000..0af5914c --- /dev/null +++ b/src/main/scala/scala/swing/ToolBar.scala @@ -0,0 +1,5 @@ +package scala.swing + +class ToolBar extends scala.swing.Component with SequentialContainer.Wrapper { + override lazy val peer: javax.swing.JToolBar = new javax.swing.JToolBar with SuperMixin +} \ No newline at end of file From 96333058833b920b6fdd09bcacf5087964fe1ce3 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 23:12:00 -0700 Subject: [PATCH 16/36] Simplify exception handling in FocusConceptsDemo by using NonFatal. --- .../examples/tutorials/misc/FocusConceptsDemo.scala | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala index 8e061b5a..4e448ed7 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala @@ -31,6 +31,7 @@ package scala.swing.examples.tutorials.misc import scala.swing._ +import scala.util.control.NonFatal /* * Tutorial: How to Use the Focus System @@ -92,14 +93,7 @@ object FocusConceptsDemo extends SimpleSwingApplication { //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); } catch { - case ex: javax.swing.UnsupportedLookAndFeelException => - ex.printStackTrace() - case ex: IllegalAccessException => - ex.printStackTrace() - case ex: InstantiationException => - ex.printStackTrace() - case ex: ClassNotFoundException => - ex.printStackTrace() + case NonFatal(ex) => ex.printStackTrace() } /* Turn off metal's use of bold fonts */ javax.swing.UIManager.put("swing.boldMetal", false); From 893b432c2e6b6ca6ee4ed070c93b67e226476411 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 23:28:18 -0700 Subject: [PATCH 17/36] Replace bad var declarations with good val declarations. --- .../tutorials/components/BorderDemo.scala | 161 +++++++++--------- 1 file changed, 80 insertions(+), 81 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala index fb60119b..06d9ecbd 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -31,7 +31,6 @@ package scala.swing.examples.tutorials.components import scala.swing._ -import javax.swing.border.TitledBorder import javax.swing.ImageIcon import java.awt.{ Color, Dimension } import java.net.URL @@ -65,53 +64,53 @@ class BorderDemo extends GridPanel(1, 0) { //a BoxPanel. //AddCompForBorder can't take a third argument that is a Panel because Panel.contents //cannot be appended to. - var label: Label = new Label("line border", Swing.EmptyIcon, Alignment.Center) - var comp: GridPanel = new GridPanel(1, 1) { - contents += label + val label1: Label = new Label("line border", Swing.EmptyIcon, Alignment.Center) + val comp1: GridPanel = new GridPanel(1, 1) { + contents += label1 border = blackline } simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp + simpleBorders.contents += comp1 // addCompForBorder(raisedetched, "raised etched border", simpleBorders) - label = new Label("raised etched border", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label2 = new Label("raised etched border", Swing.EmptyIcon, Alignment.Center) + val comp2 = new GridPanel(1, 1) { + contents += label2 border = raisedetched } simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp + simpleBorders.contents += comp2 // addCompForBorder(loweredetched, "lowered etched border", simpleBorders) - label = new Label("lowered etched border", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label3 = new Label("lowered etched border", Swing.EmptyIcon, Alignment.Center) + val comp3 = new GridPanel(1, 1) { + contents += label3 border = loweredetched } simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp + simpleBorders.contents += comp3 // addCompForBorder(raisedbevel, "raised bevel border", simpleBorders) - label = new Label("raised bevel border", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label4 = new Label("raised bevel border", Swing.EmptyIcon, Alignment.Center) + val comp4 = new GridPanel(1, 1) { + contents += label4 border = raisedbevel } simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp + simpleBorders.contents += comp4 // addCompForBorder(loweredbevel, "lowered bevel border", simpleBorders) - label = new Label("lowered bevel border", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label5 = new Label("lowered bevel border", Swing.EmptyIcon, Alignment.Center) + val comp5 = new GridPanel(1, 1) { + contents += label5 border = loweredbevel } simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp + simpleBorders.contents += comp5 // addCompForBorder(empty, "empty border", simpleBorders) - label = new Label("empty border", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label6 = new Label("empty border", Swing.EmptyIcon, Alignment.Center) + val comp6 = new GridPanel(1, 1) { + contents += label6 border = empty } simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp + simpleBorders.contents += comp6 //Second pane: matte borders val matteBorders = new BoxPanel(Orientation.Vertical) { @@ -122,47 +121,47 @@ class BorderDemo extends GridPanel(1, 0) { val border0 = Swing.MatteBorder(-1, -1, -1, -1, icon) if (icon != null) { // addCompForBorder(border, "matte border (-1,-1,-1,-1,icon)", matteBorders) - label = new Label("matte border (-1,-1,-1,-1,icon)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label7 = new Label("matte border (-1,-1,-1,-1,icon)", Swing.EmptyIcon, Alignment.Center) + val comp7 = new GridPanel(1, 1) { + contents += label7 border = border0 } matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - matteBorders.contents += comp + matteBorders.contents += comp7 } else { // addCompForBorder(border, "matte border (-1,-1,-1,-1,)", matteBorders) - label = new Label("matte border (-1,-1,-1,-1,)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label8 = new Label("matte border (-1,-1,-1,-1,)", Swing.EmptyIcon, Alignment.Center) + val comp8 = new GridPanel(1, 1) { + contents += label8 border = border0 } } val border1 = Swing.MatteBorder(1, 5, 1, 1, Color.red) // addCompForBorder(border1, "matte border (1,5,1,1,Color.red)", matteBorders) - label = new Label("matte border (1,5,1,1,Color.red)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label9 = new Label("matte border (1,5,1,1,Color.red)", Swing.EmptyIcon, Alignment.Center) + val comp9 = new GridPanel(1, 1) { + contents += label9 border = border1 } val border2 = Swing.MatteBorder(0, 20, 0, 0, icon) if (icon != null) { // addCompForBorder(border, "matte border (0,20,0,0,icon)", matteBorders) - label = new Label("matte border (0,20,0,0,icon)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label10 = new Label("matte border (0,20,0,0,icon)", Swing.EmptyIcon, Alignment.Center) + val comp10 = new GridPanel(1, 1) { + contents += label10 border = border2 } matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - matteBorders.contents += comp + matteBorders.contents += comp10 } else { // addCompForBorder(border, "matte border (0,20,0,0,)") - label = new Label("matte border (0,20,0,0,)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label11 = new Label("matte border (0,20,0,0,)", Swing.EmptyIcon, Alignment.Center) + val comp11 = new GridPanel(1, 1) { + contents += label11 border = border2 } matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - matteBorders.contents += comp + matteBorders.contents += comp11 } //Third pane: titled borders @@ -172,51 +171,51 @@ class BorderDemo extends GridPanel(1, 0) { val titled1 = Swing.TitledBorder(blackline, "title") // addCompForTitledBorder(titled1, "titled line border" + " (centered, default pos.)", // TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, titledBorders) - titled1.setTitleJustification(TitledBorder.CENTER) - titled1.setTitlePosition(TitledBorder.DEFAULT_POSITION) - label = new Label("titled line border (centered, default pos.)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + titled1.setTitleJustification(javax.swing.border.TitledBorder.CENTER) + titled1.setTitlePosition(javax.swing.border.TitledBorder.DEFAULT_POSITION) + val label12 = new Label("titled line border (centered, default pos.)", Swing.EmptyIcon, Alignment.Center) + val comp12 = new GridPanel(1, 1) { + contents += label12 border = titled1 } titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp + titledBorders.contents += comp12 val titled2 = Swing.TitledBorder(loweredetched, "title") // addCompForTitledBorder(titled2, "titled lowered etched border" + " (right just., default pos.)", // TitledBorder.RIGHT, TitledBorder.DEFAULT_POSITION, titledBorders) - titled2.setTitleJustification(TitledBorder.RIGHT) - titled2.setTitlePosition(TitledBorder.DEFAULT_POSITION) - label = new Label("titled lowered etched border (right just., default pos.)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + titled2.setTitleJustification(javax.swing.border.TitledBorder.RIGHT) + titled2.setTitlePosition(javax.swing.border.TitledBorder.DEFAULT_POSITION) + val label13 = new Label("titled lowered etched border (right just., default pos.)", Swing.EmptyIcon, Alignment.Center) + val comp13 = new GridPanel(1, 1) { + contents += label13 border = titled2 } titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp + titledBorders.contents += comp13 val titled3 = Swing.TitledBorder(loweredbevel, "title") // addCompForTitledBorder(titled3, "titled lowered bevel border" + " (default just., above top)", // TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.ABOVE_TOP, titledBorders) - titled3.setTitleJustification(TitledBorder.DEFAULT_JUSTIFICATION) - titled3.setTitlePosition(TitledBorder.ABOVE_TOP) - label = new Label("titled lowered bevel border (default just., above top)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + titled3.setTitleJustification(javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION) + titled3.setTitlePosition(javax.swing.border.TitledBorder.ABOVE_TOP) + val label14 = new Label("titled lowered bevel border (default just., above top)", Swing.EmptyIcon, Alignment.Center) + val comp14 = new GridPanel(1, 1) { + contents += label14 border = titled3 } titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp + titledBorders.contents += comp14 val titled4 = Swing.TitledBorder(empty, "title") // addCompForTitledBorder(titled4, "titled empty border" + " (default just., bottom)", // TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.BOTTOM, titledBorders) - titled4.setTitleJustification(TitledBorder.DEFAULT_JUSTIFICATION) - titled4.setTitlePosition(TitledBorder.BOTTOM) - label = new Label("titled empty border (default just., bottom)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + titled4.setTitleJustification(javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION) + titled4.setTitlePosition(javax.swing.border.TitledBorder.BOTTOM) + val label15 = new Label("titled empty border (default just., bottom)", Swing.EmptyIcon, Alignment.Center) + val comp15 = new GridPanel(1, 1) { + contents += label15 border = titled3 } titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp + titledBorders.contents += comp15 //Fourth pane: compound borders val compoundBorders = new BoxPanel(Orientation.Vertical) { @@ -225,33 +224,33 @@ class BorderDemo extends GridPanel(1, 0) { val redline = Swing.LineBorder(Color.red) val compound1 = Swing.CompoundBorder(raisedbevel, loweredbevel) // addCompForBorder(compound1, "compound border (two bevels)", compoundBorders) - label = new Label("compound border (two bevels)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label16 = new Label("compound border (two bevels)", Swing.EmptyIcon, Alignment.Center) + val comp16 = new GridPanel(1, 1) { + contents += label16 border = compound1 } compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - compoundBorders.contents += comp + compoundBorders.contents += comp16 val compound2 = Swing.CompoundBorder(redline, compound1) // addCompForBorder(compound2, "compound border (add a red outline)", compoundBorders) - label = new Label("compound border (add a red outline)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label17 = new Label("compound border (add a red outline)", Swing.EmptyIcon, Alignment.Center) + val comp17 = new GridPanel(1, 1) { + contents += label17 border = compound2 } compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - compoundBorders.contents += comp + compoundBorders.contents += comp17 val titledCompound = Swing.TitledBorder(compound2, "title") - titledCompound.setTitleJustification(TitledBorder.CENTER) - titledCompound.setTitlePosition(TitledBorder.BELOW_BOTTOM) + titledCompound.setTitleJustification(javax.swing.border.TitledBorder.CENTER) + titledCompound.setTitlePosition(javax.swing.border.TitledBorder.BELOW_BOTTOM) // addCompForBorder(titledn, "titled compound border" + " (centered, below bottom)") - label = new Label("titled compound border (centered, below bottom)", Swing.EmptyIcon, Alignment.Center) - comp = new GridPanel(1, 1) { - contents += label + val label18 = new Label("titled compound border (centered, below bottom)", Swing.EmptyIcon, Alignment.Center) + val comp18 = new GridPanel(1, 1) { + contents += label18 border = titledCompound } compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - compoundBorders.contents += comp + compoundBorders.contents += comp18 val tabbedPane = new TabbedPane() tabbedPane.pages += new TabbedPane.Page("Simple", simpleBorders) tabbedPane.pages += new TabbedPane.Page("Matte", matteBorders) From 1284635b4b03017a7dcf260d235ac325c90a3c11 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 23:30:00 -0700 Subject: [PATCH 18/36] Unused methods removed. --- .../tutorials/components/BorderDemo.scala | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala index 06d9ecbd..8dae1635 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -261,26 +261,6 @@ class BorderDemo extends GridPanel(1, 0) { tabbedPane.peer.setToolTipTextAt(1, toolTipText) contents += tabbedPane - // def addCompForTitledBorder(border: TitledBorder, - // description: String, - // justification: Int, - // position: Int, container: Panel): Unit = { - // border.setTitleJustification(justification) - // border.setTitlePosition(position) - // addCompForBorder(border, description, container) - // } - // - // def addCompForBorder(border: Border, - // description: String, container: Panel): (Component, Component) = { - // val label: Label = new Label(description, Swing.EmptyIcon, Alignment.Center) - // val comp: GridPanel = new GridPanel(1, 1) { - // contents += label - // border = border - // } - // container.contents += label - // container.contents += comp - // } - } object BorderDemo extends SimpleSwingApplication { From d01155815d3c0b3ee023f8a76467a80ed1ad99a9 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 26 Sep 2014 23:41:57 -0700 Subject: [PATCH 19/36] Copyrights and comments for ToolBar. --- src/main/scala/scala/swing/ToolBar.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/scala/scala/swing/ToolBar.scala b/src/main/scala/scala/swing/ToolBar.scala index 0af5914c..7de5d2db 100644 --- a/src/main/scala/scala/swing/ToolBar.scala +++ b/src/main/scala/scala/swing/ToolBar.scala @@ -1,5 +1,16 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + package scala.swing +/** + * Like a menu, a way to map text or icons to actions; but detachable from the rest of the user interface. + */ class ToolBar extends scala.swing.Component with SequentialContainer.Wrapper { override lazy val peer: javax.swing.JToolBar = new javax.swing.JToolBar with SuperMixin } \ No newline at end of file From 0b494f1390fc3760224e277946a7e794918c94d1 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Sat, 27 Sep 2014 11:33:21 -0700 Subject: [PATCH 20/36] Dead code removal. Null and var declaration suppression. --- .../tutorials/components/CheckboxDemo.scala | 12 +++---- .../tutorials/components/ComboBoxDemo.scala | 10 +++--- .../components/CustomComboBoxDemo.scala | 17 ++++----- .../tutorials/components/DialogDemo.scala | 11 +++--- .../components/FileChooserDemo.scala | 5 +-- .../tutorials/components/FrameDemo2.scala | 10 +++--- .../tutorials/components/IconDemoApp.scala | 8 ++--- .../tutorials/components/LabelDemo.scala | 14 ++++---- .../tutorials/components/MenuDemo.scala | 10 +++--- .../tutorials/components/MenuLookDemo.scala | 10 +++--- .../tutorials/components/PasswordDemo.scala | 11 +----- .../tutorials/components/PopupMenuDemo.scala | 10 +++--- .../components/RadioButtonDemo.scala | 12 +++---- .../tutorials/components/ScrollDemo.scala | 12 +++---- .../tutorials/components/SliderDemo2.scala | 20 +++++------ .../tutorials/components/SplitPaneDemo.scala | 15 ++++---- .../tutorials/components/SplitPaneDemo2.scala | 11 ------ .../components/SplitPaneDividerDemo.scala | 12 +++---- .../tutorials/components/TabbedPaneDemo.scala | 8 ++--- .../components/TextComponentDemo.scala | 2 +- .../components/TextSamplerDemo.scala | 35 ++++++++++--------- 21 files changed, 120 insertions(+), 135 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index 03c88e19..80026a16 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -143,11 +143,11 @@ class CheckboxDemo extends BorderPanel { def updatePicture(): Unit = { //Get the icon corresponding to the image. val s = choices.toString() - val icon: ImageIcon = CheckboxDemo.createImageIcon( + val icon: Option[ImageIcon] = CheckboxDemo.createImageIcon( "/scala/swing/examples/tutorials/images/geek/geek-" + choices.toString() + ".gif") - pictureLabel.icon = icon + pictureLabel.icon = if (icon.isDefined) icon.get else Swing.EmptyIcon pictureLabel.tooltip = choices.toString() if (icon == null) { pictureLabel.text = "Missing Image" @@ -158,13 +158,13 @@ class CheckboxDemo extends BorderPanel { } object CheckboxDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index 65e392b6..458bddab 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -58,7 +58,7 @@ class ComboBoxDemo extends BorderPanel { val imgIcon = ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + petList.selection.item + ".gif") val picture = new Label() { - icon = imgIcon + icon = if (imgIcon.isDefined) imgIcon.get else Swing.EmptyIcon font = font.deriveFont(Font.ITALIC) horizontalAlignment = Alignment.Center //The preferred size is hard-coded to be the width of the @@ -79,7 +79,7 @@ class ComboBoxDemo extends BorderPanel { def updateLabel(s: String): Unit = { val ic = ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + s + ".gif") - picture.icon = ic + picture.icon = if (ic.isDefined) imgIcon.get else Swing.EmptyIcon } } @@ -91,12 +91,12 @@ object ComboBoxDemo extends SimpleSwingApplication { val pigString = "Pig" /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index dec2d5d4..e50e9e5f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -52,7 +52,7 @@ import java.awt.{ Dimension, Font } */ class CustomComboBoxDemo extends BorderPanel { val petStrings: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig") - val images: Array[ImageIcon] = new Array[ImageIcon](petStrings.length) + val images: Array[Option[ImageIcon]] = new Array[Option[ImageIcon]](petStrings.length) val intArray: Array[Int] = new Array[Int](petStrings.length) /* * Despite its use of EmptyBorder, this panel makes a fine content @@ -63,10 +63,11 @@ class CustomComboBoxDemo extends BorderPanel { * that. */ for (i <- 0 until petStrings.length) { - images(i) = CustomComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + petStrings(i) + ".gif"); - if (images(i) != null) { - images(i).setDescription(petStrings(i)) + val oImage = CustomComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + petStrings(i) + ".gif") + if (oImage.isDefined) { + oImage.get.setDescription(petStrings(i)) } + images(i) = oImage intArray(i) = i } @@ -95,7 +96,7 @@ class CustomComboBoxDemo extends BorderPanel { a: Int, index: Int) = { //Set the icon and text. If icon was null, say so. - component.icon = images(a) + component.icon = images(a).get val pet = petStrings(a) if (component.icon != null) { component.text = pet; @@ -120,12 +121,12 @@ class CustomComboBoxDemo extends BorderPanel { object CustomComboBoxDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index bf764fd6..5f90479b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -50,7 +50,8 @@ import java.awt.{ Dimension, Font } * /scala/swing/examples/tutorials/images/middle.gif */ class DialogDemo(val frame: Frame) extends BorderPanel { - val icon: ImageIcon = DialogDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val oImage = DialogDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon: ImageIcon = if (oImage.isDefined) oImage.get else null val simpleDialogDesc = "Some simple message dialogs" val iconDesc = "A JOptionPane has its choice of icons" val moreDialogDesc = "Some more dialogs" @@ -483,13 +484,13 @@ class DialogDemo(val frame: Frame) extends BorderPanel { } object DialogDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala index d8eeeb41..8e346743 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala @@ -34,6 +34,7 @@ import scala.swing._ import scala.swing.event._ import java.io.File +import java.net.URL /* * Tutorial: How to Use File Choosers @@ -71,7 +72,7 @@ object FileChooserDemo extends SimpleSwingApplication { //Create the open button. We use the image from the JLF //Graphics Repository (but we extracted it from the jar). val openButton = new Button("Open a File...") - val openIconURL:java.net.URL = getClass().getResource("/scala/swing/examples/tutorials/images/Open16.gif") + val openIconURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/Open16.gif") if (openIconURL != null) { openButton.icon = Swing.Icon(openIconURL) } @@ -79,7 +80,7 @@ object FileChooserDemo extends SimpleSwingApplication { //Create the save button. We use the image from the JLF //Graphics Repository (but we extracted it from the jar). val saveButton = new Button("Save a File...") - val saveIconURL:java.net.URL = getClass().getResource("/scala/swing/examples/tutorials/images/Save16.gif") + val saveIconURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/Save16.gif") if (saveIconURL != null) { saveButton.icon = Swing.Icon(saveIconURL) } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index 48a1da49..2485147e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -116,7 +116,7 @@ class FrameDemo2 { f.iconImage = FrameDemo2.createFDImage() } else { //get the icon from a file - f.iconImage = FrameDemo2.getFDImage() + f.iconImage = FrameDemo2.getFDImage().get } } } @@ -282,13 +282,13 @@ object FrameDemo2 extends SimpleSwingApplication { bi } - // Returns an Image or null. - def getFDImage(): Image = { + // Returns an Image Option or None. + def getFDImage(): Option[Image] = { val imgURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/FD.jpg"); if (imgURL != null) { - return new ImageIcon(imgURL).getImage(); + return Some(new ImageIcon(imgURL).getImage) } else { - return null; + return None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index 66e54365..2dc47f8b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -124,12 +124,12 @@ class IconDemoApp extends MainFrame { override protected def doInBackground(): Unit = { println("doInBackground") for (i <- 0 until imageCaptions.length) { - val icon: ImageIcon = IconDemoApp.createImageIcon(imagedir + imageFileNames(i), imageCaptions(i)).get + val iconOption: Option[ImageIcon] = IconDemoApp.createImageIcon(imagedir + imageFileNames(i), imageCaptions(i)) val thumbAction: ThumbnailAction = - if (icon != null) { - val thumbnailIcon: ImageIcon = new ImageIcon(getScaledImage(icon.getImage(), 32, 32)) - new ThumbnailAction(icon, thumbnailIcon, imageCaptions(i)) + if (iconOption.isDefined) { + val thumbnailIcon: ImageIcon = new ImageIcon(getScaledImage(iconOption.get.getImage(), 32, 32)) + new ThumbnailAction(iconOption.get, thumbnailIcon, imageCaptions(i)) } else { // the image failed to load for some reason // so load a placeholder instead diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index c8770ad3..142d07aa 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -44,10 +44,10 @@ import java.net.URL * /scala/swing/examples/tutorials/images/middle.gif */ class LabelDemo extends GridPanel(3, 1) { - val icon: ImageIcon = LabelDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif", + val icon: Option[ImageIcon] = LabelDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif", "a pretty but meaningless splat") //Create the first label. - val label1: Label = new Label("Image and Text", icon, Alignment.Center) { + val label1: Label = new Label("Image and Text", icon.get, Alignment.Center) { //Set the position of its text, relative to its icon: verticalTextPosition = Alignment.Bottom horizontalTextPosition = Alignment.Center @@ -55,7 +55,7 @@ class LabelDemo extends GridPanel(3, 1) { //Create the other labels. val label2 = new Label("Text-Only Label") - val label3 = new Label("", icon, Alignment.Center) + val label3 = new Label("", icon.get, Alignment.Center) //Create tool tips, for the heck of it. label1.tooltip = "A label containing both image and text" @@ -68,14 +68,14 @@ class LabelDemo extends GridPanel(3, 1) { } object LabelDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String, description: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String, description: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL, description) + Some(new ImageIcon(imgURL, description)) } else { - null + None } } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index 73f18162..78fc113c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -74,7 +74,7 @@ class MenuDemo extends BorderPanel { } menu.contents += menuItem1 // - val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get val menuItem2 = new MenuItem("Both text and icon") { icon = icon mnemonic = Key.B @@ -200,13 +200,13 @@ class MenuDemo extends BorderPanel { } object MenuDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon icon, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala index f6b8798f..5b6f81fc 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -74,7 +74,7 @@ class MenuLookDemo extends BorderPanel { } menu.contents += menuItem1 // - val icon: ImageIcon = MenuLookDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon: ImageIcon = MenuLookDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get val menuItem2 = new MenuItem("Both text and icon") { icon = icon mnemonic = Key.B @@ -170,13 +170,13 @@ class MenuLookDemo extends BorderPanel { } object MenuLookDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala index 139b0d03..0b652e46 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala @@ -71,16 +71,7 @@ object PasswordDemo extends SimpleSwingApplication { */ def isPasswordCorrect(input: Array[Char]): Boolean = { val correctPassword = Array[Char]('b', 'u', 'g', 'a', 'b', 'o', 'o') - - val isCorrect = if (input.length != correctPassword.length) { - false; - } else { - var same = true - for (i <- 0 until input.length) { - same &= input(i) == correctPassword(i) - } - same - } + val isCorrect = input.deep == correctPassword.deep //Zero out the password. // Arrays.fill(correctPassword,'0'); diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala index cc9d13ed..d635e0ee 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -77,7 +77,7 @@ class PopupMenuDemo extends BorderPanel { } menu.contents += menuItem1 // - val icon: ImageIcon = PopupMenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon: ImageIcon = PopupMenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get val menuItem2 = new MenuItem("Both text and icon") { icon = icon mnemonic = Key.B @@ -236,13 +236,13 @@ class PopupMenuDemo extends BorderPanel { } object PopupMenuDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } /** diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index 6c47c10f..99749ba3 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -85,7 +85,7 @@ class RadioButtonDemo extends BorderPanel { + RadioButtonDemo.birdString + ".gif") val picture = new Label() { - icon = imgIcon + icon = imgIcon.get //The preferred size is hard-coded to be the width of the //widest image and the height of the tallest image. //A real program would compute this. @@ -121,7 +121,7 @@ class RadioButtonDemo extends BorderPanel { } def getPictureIcon(gifName: String): ImageIcon = { - RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + gifName + ".gif") + RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + gifName + ".gif").get } } @@ -132,13 +132,13 @@ object RadioButtonDemo extends SimpleSwingApplication { val rabbitString = "Rabbit" val pigString = "Pig" - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - Swing.Icon(imgURL) + Some(Swing.Icon(imgURL)) } else { - null + None } } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala index f8d61f31..a1eb43ca 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -55,7 +55,7 @@ import scala.swing.event.ButtonClicked */ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { //Get the image to use. - val bee: ImageIcon = ScrollDemo.createImageIcon("/scala/swing/examples/tutorials/images/flyingBee.jpg") + val bee: ImageIcon = ScrollDemo.createImageIcon("/scala/swing/examples/tutorials/images/flyingBee.jpg").get //Create the row and column headers. val columnView = new Rule(Rule.Horizontal, true); @@ -118,14 +118,14 @@ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { } object ScrollDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) + // scala swing has no mechanism for setting the description in the peer. + Some(new ImageIcon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 39bd0c31..9094e8ed 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -56,7 +56,7 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { val FpsInit = 15; //initial frames per second var frameNumber = 0 val NumFrames = 14 - val images = new Array[ImageIcon](NumFrames) + val images = new Array[Option[ImageIcon]](NumFrames) var frozen = false var delay = 1000 / FpsInit @@ -154,14 +154,14 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { def updatePicture(frameNum: Int): Unit = { //Get the image if we haven't already. if (images(frameNumber) == null) { - images(frameNumber) = SliderDemo.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" + images(frameNumber) = SliderDemo2.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" + frameNumber - + ".gif"); + + ".gif") } //Set the image. - if (images(frameNumber) != null) { - picture.icon = images(frameNumber) + if (images(frameNumber).isDefined) { + picture.icon = images(frameNumber).get } else { //image not found picture.text = "image #" + frameNumber + " not found" } @@ -169,14 +169,14 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { } object SliderDemo2 extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { - // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) + // scala swing has no mechanism for setting the description in the peer. + Some(new ImageIcon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index 35886011..a133732b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -79,12 +79,13 @@ class SplitPaneDemo extends FlowPanel { //Renders the selected image def updateLabel (name: String): Unit = { - val icon: ImageIcon = SplitPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + name + ".gif"); - picture.icon = icon - if (icon != null) { + val icon: Option[ImageIcon] = SplitPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + name + ".gif") + if (icon.isDefined) { picture.text = null + picture.icon = icon.get } else { picture.text = "Image not found" + picture.icon = null } } @@ -99,14 +100,14 @@ class SplitPaneDemo extends FlowPanel { } object SplitPaneDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or NOne if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) + Some(new ImageIcon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala index 02fd467d..edde1138 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -93,17 +93,6 @@ class SplitPaneDemo2 extends MainFrame { } object SplitPaneDemo2 extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) - } else { - null - } - } - lazy val top = new SplitPaneDemo2() } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index 04e01b41..18141a7a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -52,13 +52,13 @@ import javax.swing.ImageIcon */ class SplitPaneDividerDemo extends BorderPanel { font = new Font("Serif", Font.ITALIC, 24) - val icon1 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Cat.gif") + val icon1 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Cat.gif").get val sd1 = new SizeDisplayer("left", icon1) { font = font } sd1.setMinimumSize(new Dimension(30,30)) - val icon2 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Dog.gif") + val icon2 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Dog.gif").get val sd2 = new SizeDisplayer("right", icon2) { font = font } @@ -87,14 +87,14 @@ class SplitPaneDividerDemo extends BorderPanel { } object SplitPaneDividerDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) + Some(new ImageIcon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala index 8118d419..ce8e24f9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala @@ -47,7 +47,7 @@ import javax.swing.ImageIcon */ class TabbedPaneDemo extends GridPanel(1, 1) { val tabbedPane = new TabbedPane() - val icon1: ImageIcon = TabbedPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val icon1: ImageIcon = TabbedPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get val panel1: Panel = makeTextPanel("Panel #1") tabbedPane.pages += new TabbedPane.Page("Tab 1", panel1, "Does nothing") tabbedPane.pages(0).mnemonic = 1 @@ -81,13 +81,13 @@ class TabbedPaneDemo extends GridPanel(1, 1) { object TabbedPaneDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { + def createImageIcon(path: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) if (imgURL != null) { // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) + Some(new ImageIcon(imgURL)) } else { - null + None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index cab22c3f..b988ef08 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -342,7 +342,7 @@ class TextComponentDemo extends MainFrame { //The following two methods allow us to find an //action provided by the editor kit by its name. def createActionTable(textComponent: TextComponent): HashMap[String, javax.swing.Action] = { - var hm = new HashMap[String, javax.swing.Action]() + val hm = new HashMap[String, javax.swing.Action]() for (a <- textComponent.peer.getActions()) { val s = a.getValue(javax.swing.Action.NAME).asInstanceOf[String] hm.put(s, a) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala index 07c4316f..7747bbf1 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -31,10 +31,11 @@ package scala.swing.examples.tutorials.components -import java.awt.{ Cursor, Font, Toolkit } -import javax.swing.text.{ StyleConstants, StyleContext } import scala.swing._ import scala.swing.event._ +import java.awt.{ Cursor, Font, Toolkit } +import java.net.URL +import javax.swing.text.{ StyleConstants, StyleContext } /* * Tutorials: How to Use Text Components @@ -155,7 +156,7 @@ object TextSamplerDemo extends SimpleSwingApplication { //To get this to work in Eclipse, add /src/main/resources directory to the run //configuration classpath. The file TextSamplerDemoHelp.html is placed in that //directory. - val helpURL: java.net.URL = getClass().getResource("/scala/swing/examples/tutorials/TextSamplerDemoHelp.html") + val helpURL: URL = getClass().getResource("/scala/swing/examples/tutorials/TextSamplerDemoHelp.html") if (helpURL != null) { editorPane.editorKit = new javax.swing.text.html.HTMLEditorKit @@ -227,22 +228,22 @@ object TextSamplerDemo extends SimpleSwingApplication { val `def` = StyleContext.getDefaultStyleContext.getStyle(StyleContext.DEFAULT_STYLE) val regular = doc.addStyle("regular", `def`) StyleConstants.setFontFamily(`def`, "SansSerif") - var s = doc.addStyle("italic", regular) - StyleConstants.setItalic(s, true) - s = doc.addStyle("bold", regular) - StyleConstants.setBold(s, true) - s = doc.addStyle("small", regular) - StyleConstants.setFontSize(s, 10) - s = doc.addStyle("large", regular) - StyleConstants.setFontSize(s, 16) - s = doc.addStyle("icon", regular) - StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER) + val sItalic = doc.addStyle("italic", regular) + StyleConstants.setItalic(sItalic, true) + val sBold = doc.addStyle("bold", regular) + StyleConstants.setBold(sBold, true) + val sSmall = doc.addStyle("small", regular) + StyleConstants.setFontSize(sSmall, 10) + val sLarge = doc.addStyle("large", regular) + StyleConstants.setFontSize(sLarge, 16) + val sIcon = doc.addStyle("icon", regular) + StyleConstants.setAlignment(sIcon, StyleConstants.ALIGN_CENTER) val pigIcon = createImageIcon("/scala/swing/examples/tutorials/images/Pig.gif", "a cute pig") if (pigIcon != None) { - StyleConstants.setIcon(s, pigIcon.get) + StyleConstants.setIcon(sIcon, pigIcon.get) } - s = doc.addStyle("button", regular) - StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER) + val sButton = doc.addStyle("button", regular) + StyleConstants.setAlignment(sButton, StyleConstants.ALIGN_CENTER) val soundIcon = createImageIcon("/scala/swing/examples/tutorials/images/sound.gif", "sound icon") // button = new Button() if (soundIcon != None) { @@ -254,7 +255,7 @@ object TextSamplerDemo extends SimpleSwingApplication { button.margin = new Insets(0, 0, 0, 0) // button.setActionCommand(buttonString) // button.addActionListener(this) - StyleConstants.setComponent(s, button.peer) + StyleConstants.setComponent(sButton, button.peer) } def createTextPane(button: Button): TextPane = { From 282aa7e63cde0d94ae5513e0573dbb58c4fb7a7a Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Sat, 27 Sep 2014 11:52:23 -0700 Subject: [PATCH 21/36] Return an ImageIcon option instead of an ImageIcon from the createNavigationIcon function. --- .../examples/tutorials/misc/ActionDemo.scala | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala index 0fe7388b..675c86af 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala @@ -65,21 +65,21 @@ class ActionDemo extends BorderPanel { val leftAction = new LeftAction() class LeftAction extends Action("Go left") { override def apply(): Unit = {} - icon = ActionDemo.createNavigationIcon("Back24") + icon = ActionDemo.createNavigationIcon("Back24").get mnemonic = new Integer(java.awt.event.KeyEvent.VK_L) peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the left button.") // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) } val middleAction = new Action("Do something") { override def apply(): Unit = {} - icon = ActionDemo.createNavigationIcon("Up24") + icon = ActionDemo.createNavigationIcon("Up24").get mnemonic = new Integer(java.awt.event.KeyEvent.VK_M) peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the middle button.") // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) } val rightAction = new Action("Go right") { override def apply(): Unit = {} - icon = ActionDemo.createNavigationIcon("Forward24") + icon = ActionDemo.createNavigationIcon("Forward24").get mnemonic = new Integer(java.awt.event.KeyEvent.VK_R) peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the right button.") // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) @@ -174,16 +174,15 @@ class ActionDemo extends BorderPanel { } object ActionDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createNavigationIcon(imageName: String): ImageIcon = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createNavigationIcon(imageName: String): Option[ImageIcon] = { val imgLocation = "/toolbarButtonGraphics/navigation/" + imageName + ".gif" val imageURL: URL = getClass().getResource(imgLocation) - if (imageURL == null) { System.err.println("Resource not found: " + imgLocation) - return null + return None } else { - return new ImageIcon(imageURL) + return Some(new ImageIcon(imageURL)) } } From 7af611244f74a764ac69a32bd9e8b03f528e36a9 Mon Sep 17 00:00:00 2001 From: andy1138 Date: Mon, 29 Sep 2014 13:03:50 +0100 Subject: [PATCH 22/36] BorderDemo little closer to original --- .../tutorials/components/BorderDemo.scala | 301 ++++++------------ 1 file changed, 89 insertions(+), 212 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala index 8dae1635..c7bece13 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -31,253 +31,130 @@ package scala.swing.examples.tutorials.components import scala.swing._ -import javax.swing.ImageIcon -import java.awt.{ Color, Dimension } -import java.net.URL +import java.awt.Color -/* +/** * Tutorial: How to Use Borders - * http://docs.oracle.com/javase/tutorial/uiswing/components/border.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/border.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/BorderDemoProject/src/components/BorderDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/BorderDemoProject/src/components/BorderDemo.java]] * * BorderDemo.scala requires the following file: * scala/swing/examples/tutorials/images/wavy.gif */ class BorderDemo extends GridPanel(1, 0) { - //A border that puts 10 extra pixels at the sides and - //bottom of each pane. - val paneEdge = Swing.EmptyBorder(0, 10, 10, 10) - val blackline = Swing.LineBorder(Color.black); - val raisedetched = Swing.EtchedBorder(Swing.Raised) - val loweredetched = Swing.EtchedBorder(Swing.Lowered) - val raisedbevel = Swing.BeveledBorder(Swing.Raised) - val loweredbevel = Swing.BeveledBorder(Swing.Lowered) - val empty = Swing.EmptyBorder + private val paneEdge = Swing.EmptyBorder(0, 10, 10, 10) + private val blackline = Swing.LineBorder(Color.black) + private val raisedetched = Swing.EtchedBorder(Swing.Raised) + private val loweredetched = Swing.EtchedBorder(Swing.Lowered) + private val raisedbevel = Swing.BeveledBorder(Swing.Raised) + private val loweredbevel = Swing.BeveledBorder(Swing.Lowered) + private val empty = Swing.EmptyBorder + + + def addCompForBorder(bord: javax.swing.border.Border, description: String): Seq[Component] = + List(Swing.RigidBox(new Dimension(0, 10)), new GridPanel(1, 1) { + contents += new Label(description, Swing.EmptyIcon, Alignment.Center) + border = bord + }) //First pane: simple borders - val simpleBorders = new BoxPanel(Orientation.Vertical) - //The method addCompForBorder in the original Java did not have a useful Scala translation - //because adding to Panel contents is not the same as adding to the contents of, say, - //a BoxPanel. - //AddCompForBorder can't take a third argument that is a Panel because Panel.contents - //cannot be appended to. - val label1: Label = new Label("line border", Swing.EmptyIcon, Alignment.Center) - val comp1: GridPanel = new GridPanel(1, 1) { - contents += label1 - border = blackline - } - simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp1 - // addCompForBorder(raisedetched, "raised etched border", simpleBorders) - val label2 = new Label("raised etched border", Swing.EmptyIcon, Alignment.Center) - val comp2 = new GridPanel(1, 1) { - contents += label2 - border = raisedetched - } - simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp2 - // addCompForBorder(loweredetched, "lowered etched border", simpleBorders) - val label3 = new Label("lowered etched border", Swing.EmptyIcon, Alignment.Center) - val comp3 = new GridPanel(1, 1) { - contents += label3 - border = loweredetched + val simpleBorders = new BoxPanel(Orientation.Vertical) { + contents ++= + addCompForBorder(blackline, "line border") ++ + addCompForBorder(raisedetched, "raised etched border") ++ + addCompForBorder(loweredetched, "lowered etched border") ++ + addCompForBorder(raisedbevel, "raised bevel border") ++ + addCompForBorder(loweredbevel, "lowered bevel border") ++ + addCompForBorder(empty, "empty border") } - simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp3 - // addCompForBorder(raisedbevel, "raised bevel border", simpleBorders) - val label4 = new Label("raised bevel border", Swing.EmptyIcon, Alignment.Center) - val comp4 = new GridPanel(1, 1) { - contents += label4 - border = raisedbevel - } - simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp4 - // addCompForBorder(loweredbevel, "lowered bevel border", simpleBorders) - val label5 = new Label("lowered bevel border", Swing.EmptyIcon, Alignment.Center) - val comp5 = new GridPanel(1, 1) { - contents += label5 - border = loweredbevel - } - simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp5 - // addCompForBorder(empty, "empty border", simpleBorders) - val label6 = new Label("empty border", Swing.EmptyIcon, Alignment.Center) - val comp6 = new GridPanel(1, 1) { - contents += label6 - border = empty - } - simpleBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - simpleBorders.contents += comp6 //Second pane: matte borders val matteBorders = new BoxPanel(Orientation.Vertical) { border = paneEdge - } - val icon: ImageIcon = BorderDemo.createImageIcon("/scala/swing/examples/tutorials/images/wavy.gif", - "wavy-line border icon"); //20x22 - val border0 = Swing.MatteBorder(-1, -1, -1, -1, icon) - if (icon != null) { - // addCompForBorder(border, "matte border (-1,-1,-1,-1,icon)", matteBorders) - val label7 = new Label("matte border (-1,-1,-1,-1,icon)", Swing.EmptyIcon, Alignment.Center) - val comp7 = new GridPanel(1, 1) { - contents += label7 - border = border0 - } - matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - matteBorders.contents += comp7 - } else { - // addCompForBorder(border, "matte border (-1,-1,-1,-1,)", matteBorders) - val label8 = new Label("matte border (-1,-1,-1,-1,)", Swing.EmptyIcon, Alignment.Center) - val comp8 = new GridPanel(1, 1) { - contents += label8 - border = border0 - } - } - val border1 = Swing.MatteBorder(1, 5, 1, 1, Color.red) - // addCompForBorder(border1, "matte border (1,5,1,1,Color.red)", matteBorders) - val label9 = new Label("matte border (1,5,1,1,Color.red)", Swing.EmptyIcon, Alignment.Center) - val comp9 = new GridPanel(1, 1) { - contents += label9 - border = border1 - } - val border2 = Swing.MatteBorder(0, 20, 0, 0, icon) - if (icon != null) { - // addCompForBorder(border, "matte border (0,20,0,0,icon)", matteBorders) - val label10 = new Label("matte border (0,20,0,0,icon)", Swing.EmptyIcon, Alignment.Center) - val comp10 = new GridPanel(1, 1) { - contents += label10 - border = border2 - } - matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - matteBorders.contents += comp10 - } else { - // addCompForBorder(border, "matte border (0,20,0,0,)") - val label11 = new Label("matte border (0,20,0,0,)", Swing.EmptyIcon, Alignment.Center) - val comp11 = new GridPanel(1, 1) { - contents += label11 - border = border2 - } - matteBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - matteBorders.contents += comp11 + + val icon = BorderDemo.createImageIcon("/scala/swing/examples/tutorials/images/wavy.gif", "wavy-line border icon") + + contents ++= + addCompForBorder( + Swing.MatteBorder(-1, -1, -1, -1, icon.getOrElse(null.asInstanceOf[javax.swing.Icon])), + "matte border (-1,-1,-1,-1,icon)") ++ + addCompForBorder( + Swing.MatteBorder(1, 5, 1, 1, Color.red), + "matte border (1,5,1,1,Color.red)") ++ + addCompForBorder( + Swing.MatteBorder(0, 20, 0, 0, icon.getOrElse(null.asInstanceOf[javax.swing.Icon])), + "matte border (0,20,0,0,icon)") } //Third pane: titled borders val titledBorders = new BoxPanel(Orientation.Vertical) { border = paneEdge + + def titleBorder(border: javax.swing.border.Border, justification: Int, position: Int): javax.swing.border.Border = { + val titled = Swing.TitledBorder(border, "title") + titled.setTitleJustification(justification) + titled.setTitlePosition(position) + titled + } + + contents ++= + addCompForBorder( + titleBorder(blackline, javax.swing.border.TitledBorder.CENTER, javax.swing.border.TitledBorder.DEFAULT_POSITION), + "titled line border (centered, default pos.)") ++ + addCompForBorder( + titleBorder(loweredetched, javax.swing.border.TitledBorder.RIGHT, javax.swing.border.TitledBorder.DEFAULT_POSITION), + "titled lowered etched border (right just., default pos.)") ++ + addCompForBorder( + titleBorder(loweredbevel, javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.ABOVE_TOP), + "titled lowered bevel border (default just., above top)") ++ + addCompForBorder( + titleBorder(empty, javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.BOTTOM), + "titled empty border (default just., bottom)") } - val titled1 = Swing.TitledBorder(blackline, "title") - // addCompForTitledBorder(titled1, "titled line border" + " (centered, default pos.)", - // TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, titledBorders) - titled1.setTitleJustification(javax.swing.border.TitledBorder.CENTER) - titled1.setTitlePosition(javax.swing.border.TitledBorder.DEFAULT_POSITION) - val label12 = new Label("titled line border (centered, default pos.)", Swing.EmptyIcon, Alignment.Center) - val comp12 = new GridPanel(1, 1) { - contents += label12 - border = titled1 - } - titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp12 - val titled2 = Swing.TitledBorder(loweredetched, "title") - // addCompForTitledBorder(titled2, "titled lowered etched border" + " (right just., default pos.)", - // TitledBorder.RIGHT, TitledBorder.DEFAULT_POSITION, titledBorders) - titled2.setTitleJustification(javax.swing.border.TitledBorder.RIGHT) - titled2.setTitlePosition(javax.swing.border.TitledBorder.DEFAULT_POSITION) - val label13 = new Label("titled lowered etched border (right just., default pos.)", Swing.EmptyIcon, Alignment.Center) - val comp13 = new GridPanel(1, 1) { - contents += label13 - border = titled2 - } - titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp13 - val titled3 = Swing.TitledBorder(loweredbevel, "title") - // addCompForTitledBorder(titled3, "titled lowered bevel border" + " (default just., above top)", - // TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.ABOVE_TOP, titledBorders) - titled3.setTitleJustification(javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION) - titled3.setTitlePosition(javax.swing.border.TitledBorder.ABOVE_TOP) - val label14 = new Label("titled lowered bevel border (default just., above top)", Swing.EmptyIcon, Alignment.Center) - val comp14 = new GridPanel(1, 1) { - contents += label14 - border = titled3 - } - titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp14 - val titled4 = Swing.TitledBorder(empty, "title") - // addCompForTitledBorder(titled4, "titled empty border" + " (default just., bottom)", - // TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.BOTTOM, titledBorders) - titled4.setTitleJustification(javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION) - titled4.setTitlePosition(javax.swing.border.TitledBorder.BOTTOM) - val label15 = new Label("titled empty border (default just., bottom)", Swing.EmptyIcon, Alignment.Center) - val comp15 = new GridPanel(1, 1) { - contents += label15 - border = titled3 - } - titledBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - titledBorders.contents += comp15 //Fourth pane: compound borders val compoundBorders = new BoxPanel(Orientation.Vertical) { border = paneEdge + + val titledCompound = Swing.TitledBorder(Swing.CompoundBorder(Swing.LineBorder(Color.red), Swing.CompoundBorder(Swing.BeveledBorder(Swing.Raised), Swing.BeveledBorder(Swing.Lowered))), "title") + titledCompound.setTitleJustification(javax.swing.border.TitledBorder.CENTER) + titledCompound.setTitlePosition(javax.swing.border.TitledBorder.BELOW_BOTTOM) + + contents ++= + addCompForBorder( + Swing.CompoundBorder(raisedbevel, loweredbevel), + "compound border (two bevels)") ++ + addCompForBorder( + Swing.CompoundBorder(Swing.LineBorder(Color.red), Swing.CompoundBorder(raisedbevel, loweredbevel)), + "compound border (add a red outline)") ++ + addCompForBorder( + titledCompound, + "titled compound border (centered, below bottom)") } - val redline = Swing.LineBorder(Color.red) - val compound1 = Swing.CompoundBorder(raisedbevel, loweredbevel) - // addCompForBorder(compound1, "compound border (two bevels)", compoundBorders) - val label16 = new Label("compound border (two bevels)", Swing.EmptyIcon, Alignment.Center) - val comp16 = new GridPanel(1, 1) { - contents += label16 - border = compound1 - } - compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - compoundBorders.contents += comp16 - val compound2 = Swing.CompoundBorder(redline, compound1) - // addCompForBorder(compound2, "compound border (add a red outline)", compoundBorders) - val label17 = new Label("compound border (add a red outline)", Swing.EmptyIcon, Alignment.Center) - val comp17 = new GridPanel(1, 1) { - contents += label17 - border = compound2 - } - compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - compoundBorders.contents += comp17 - val titledCompound = Swing.TitledBorder(compound2, "title") - titledCompound.setTitleJustification(javax.swing.border.TitledBorder.CENTER) - titledCompound.setTitlePosition(javax.swing.border.TitledBorder.BELOW_BOTTOM) - // addCompForBorder(titledn, "titled compound border" + " (centered, below bottom)") - val label18 = new Label("titled compound border (centered, below bottom)", Swing.EmptyIcon, Alignment.Center) - val comp18 = new GridPanel(1, 1) { - contents += label18 - border = titledCompound - } - compoundBorders.contents += Swing.RigidBox(new Dimension(0, 10)) - compoundBorders.contents += comp18 - val tabbedPane = new TabbedPane() - tabbedPane.pages += new TabbedPane.Page("Simple", simpleBorders) - tabbedPane.pages += new TabbedPane.Page("Matte", matteBorders) - tabbedPane.pages += new TabbedPane.Page("Titled", titledBorders) - tabbedPane.pages += new TabbedPane.Page("Compound", compoundBorders) - tabbedPane.selection.index = 0 - val toolTipText = "Blue Wavy Line border art crew:
   Bill Pauley
   Cris St. Aubyn
   Ben Wronsky
   Nathan Walrath
   Tommy Adams, special consultant" - tabbedPane.peer.setToolTipTextAt(1, toolTipText) - contents += tabbedPane + + contents += new TabbedPane() { + tooltip = "Blue Wavy Line border art crew:
   Bill Pauley
   Cris St. Aubyn
   Ben Wronsky
   Nathan Walrath
   Tommy Adams, special consultant" + + pages += new TabbedPane.Page("Simple", simpleBorders) + pages += new TabbedPane.Page("Matte", matteBorders) + pages += new TabbedPane.Page("Titled", titledBorders) + pages += new TabbedPane.Page("Compound", compoundBorders) + + selection.index = 0 + } } object BorderDemo extends SimpleSwingApplication { + def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - def createImageIcon(path: String, description: String): ImageIcon = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - new ImageIcon(imgURL, description) - } else { - System.err.println("Couldn't find file: " + path); - null - } - } - lazy val top = new MainFrame() { title = "BorderDemo" //Create and set up the content pane. - contents = new BorderDemo(); + contents = new BorderDemo() } } \ No newline at end of file From a6f21c8bb0e1d5c6565c0c64e10d4d4033296863 Mon Sep 17 00:00:00 2001 From: andy1138 Date: Mon, 29 Sep 2014 13:08:57 +0100 Subject: [PATCH 23/36] BorderDemo little closer to original --- .../tutorials/components/BorderDemo.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala index c7bece13..47fbae37 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/BorderDemo.scala @@ -36,7 +36,7 @@ import java.awt.Color /** * Tutorial: How to Use Borders * [[http://docs.oracle.com/javase/tutorial/uiswing/components/border.html]] - * + * * Source code reference: * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/BorderDemoProject/src/components/BorderDemo.java]] * @@ -45,13 +45,13 @@ import java.awt.Color */ class BorderDemo extends GridPanel(1, 0) { - private val paneEdge = Swing.EmptyBorder(0, 10, 10, 10) - private val blackline = Swing.LineBorder(Color.black) - private val raisedetched = Swing.EtchedBorder(Swing.Raised) - private val loweredetched = Swing.EtchedBorder(Swing.Lowered) - private val raisedbevel = Swing.BeveledBorder(Swing.Raised) - private val loweredbevel = Swing.BeveledBorder(Swing.Lowered) - private val empty = Swing.EmptyBorder + val paneEdge = Swing.EmptyBorder(0, 10, 10, 10) + val blackline = Swing.LineBorder(Color.black) + val raisedetched = Swing.EtchedBorder(Swing.Raised) + val loweredetched = Swing.EtchedBorder(Swing.Lowered) + val raisedbevel = Swing.BeveledBorder(Swing.Raised) + val loweredbevel = Swing.BeveledBorder(Swing.Lowered) + val empty = Swing.EmptyBorder def addCompForBorder(bord: javax.swing.border.Border, description: String): Seq[Component] = From ef3aadbc374197991dc357613d8b73afcfdb20ad Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Tue, 30 Sep 2014 10:43:22 -0700 Subject: [PATCH 24/36] Moved look and feel setup code to get rid of some more statements that accessed MainFrame's peer. Used the right scala-swing code to do alignment, improving the appearance of some applications and also removing more accesses to various component peers. Added new tutorials for layouts. --- .../examples/tutorials/images/geek-cght.gif | Bin 0 -> 4997 bytes .../tutorials/components/ButtonDemo.scala | 4 +- .../tutorials/components/ComboBoxDemo2.scala | 7 +- .../components/FormattedTextFieldDemo.scala | 6 +- .../tutorials/components/FrameDemo2.scala | 28 +-- .../tutorials/components/HtmlDemo.scala | 4 +- .../tutorials/components/LabelDemo.scala | 4 +- .../tutorials/components/ListDialog.scala | 3 +- .../components/ListDialogRunner.scala | 9 +- .../tutorials/components/SliderDemo.scala | 10 +- .../tutorials/components/SliderDemo2.scala | 2 +- .../tutorials/components/TablePrintDemo.scala | 4 +- .../components/TextComponentDemo.scala | 6 +- .../tutorials/layout/BLDComponent.scala | 96 ++++++++++ .../tutorials/layout/BorderLayoutDemo.scala | 74 +++++++ .../tutorials/layout/BoxAlignmentDemo.scala | 170 ++++++++++++++++ .../tutorials/layout/BoxLayoutDemo.scala | 73 +++++++ .../tutorials/layout/BoxLayoutDemo2.scala | 107 +++++++++++ .../tutorials/layout/CustomLayoutDemo.scala | 66 +++++++ .../tutorials/layout/DiagonalLayout.scala | 181 ++++++++++++++++++ .../tutorials/layout/FlowLayoutDemo.scala | 60 ++++++ .../tutorials/misc/FocusConceptsDemo.scala | 6 +- 22 files changed, 874 insertions(+), 46 deletions(-) create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/geek-cght.gif create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/BLDComponent.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/geek-cght.gif b/examples/src/main/resources/scala/swing/examples/tutorials/images/geek-cght.gif new file mode 100644 index 0000000000000000000000000000000000000000..4e1299258cda297c85fb24c9aceeec1064e46815 GIT binary patch literal 4997 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 ; + } + //Make sure we have nice window decorations. + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + //Creates an icon-worthy Image from scratch. def createFDImage(): Image = { //Create a 16x16 pixel image. @@ -294,26 +307,13 @@ object FrameDemo2 extends SimpleSwingApplication { lazy val top = new Frame() { title = "FrameDemo2" - //Use the Java look and feel. This needs to be done before the frame is created - //so the companion object FrameDemo2 cannot simply extend SimpleSwingApplcation. - try { - UIManager.setLookAndFeel( - UIManager.getCrossPlatformLookAndFeelClassName()); - } catch { - case e: Exception => ; - } - //Make sure we have nice window decorations. - JFrame.setDefaultLookAndFeelDecorated(true); - JDialog.setDefaultLookAndFeelDecorated(true); //Create and set up the content pane. val demo = new FrameDemo2(); //Add components to it. val contentPane = peer.getContentPane() - } top.contentPane.add(top.demo.createOptionControls(top), BorderLayout.CENTER) top.contentPane.add(top.demo.createButtonPane(top), BorderLayout.PAGE_END) - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala index 12e3aa3c..84db4d65 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala @@ -62,8 +62,8 @@ class HtmlDemo extends BoxPanel(Orientation.Horizontal) { val scrollPane = new ScrollPane(htmlTextArea) val changeTheLabel = new Button("Change the label") { mnemonic = Key.C - // xAlignment = Alignment.Center - peer.setAlignmentX(Component.CENTER_ALIGNMENT) + // peer.setAlignmentX(Component.CENTER_ALIGNMENT) + xLayoutAlignment = 0.50 // Center } val theLabel = new Label(initialText) { minimumSize = new Dimension(200, 200) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index 142d07aa..b6d16044 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -33,6 +33,7 @@ package scala.swing.examples.tutorials.components import scala.swing._ import javax.swing.ImageIcon import java.net.URL +import javax.swing.UIManager /* * Tutorial: How to Use Labels * http://docs.oracle.com/javase/tutorial/uiswing/components/label.html @@ -68,6 +69,7 @@ class LabelDemo extends GridPanel(3, 1) { } object LabelDemo extends SimpleSwingApplication { + UIManager.put("swing.boldMetal", false) /** Returns an ImageIcon option, or None if the path was invalid. */ def createImageIcon(path: String, description: String): Option[ImageIcon] = { val imgURL: URL = getClass().getResource(path) @@ -81,8 +83,6 @@ object LabelDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "LabelDemo" //Create and set up the content pane. - javax.swing.UIManager.put("swing.boldMetal", false) contents = new LabelDemo(); } - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala index d651cd57..5ff206fa 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala @@ -81,7 +81,8 @@ class ListDialog(frame: Frame, locationComp: Component, // val listScroller = new ScrollPane(list) { preferredSize = new Dimension(250, 80) - peer.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT) + // peer.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT) + xLayoutAlignment = 0.0 // Left } // //Create a container so that we can add a title around diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala index d5b86bc0..c72d580f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala @@ -50,16 +50,21 @@ class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) "Otto", "Ringo", "Rocco", "Rollo") //Create the labels. - val intro = new Label("The chosen name:") + val intro = new Label("The chosen name:") { + xLayoutAlignment = 0.50 // Center + } val nameLabel = new Label(names(1)) { //Use a wacky font if it exists. If not, this falls //back to a font we know exists. font = getAFont() + xLayoutAlignment = 0.50 // Center } intro.peer.setLabelFor(nameLabel.peer) //Create the button. - val button = new Button("Pick a new name...") + val button = new Button("Pick a new name...") { + xLayoutAlignment = 0.50 // Center + } contents += intro contents += nameLabel diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index 0bf618d9..721d7590 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -37,7 +37,7 @@ import java.awt.Font import java.awt.event.{ ActionEvent, ActionListener } import javax.swing.Timer import java.net.URL -import javax.swing.ImageIcon +import javax.swing.{ImageIcon, UIManager} /* * Tutorial: How to Use Sliders @@ -62,7 +62,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act val sliderLabel = new Label("Frames Per Second") { horizontalAlignment = Alignment.Center - xAlignment = Alignment.Center + xLayoutAlignment = 0.50 // Center } val framesPerSecond = new Slider { @@ -81,7 +81,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act val picture = new Label() { horizontalAlignment = Alignment.Center - xAlignment = Alignment.Center + xLayoutAlignment = 0.50 // Center Swing.Lowered border = Swing.CompoundBorder( Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) @@ -170,6 +170,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act } object SliderDemo extends SimpleSwingApplication { + UIManager.put("swing.boldMetal", false) /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String): ImageIcon = { val imgURL: URL = getClass().getResource(path) @@ -183,11 +184,8 @@ object SliderDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "SliderDemo" - javax.swing.UIManager.put("swing.boldMetal", false) //Create and set up the content pane. contents = new SliderDemo(this); } - - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 9094e8ed..6714f229 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -81,7 +81,7 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { val picture = new Label() { horizontalAlignment = Alignment.Center - xAlignment = Alignment.Center + xLayoutAlignment = 0.50 // Center Swing.Lowered border = Swing.CompoundBorder( Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala index 50e0ce4f..0134acad 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala @@ -64,8 +64,8 @@ class TablePrintDemo extends BoxPanel(Orientation.Vertical) { //Add a print button. val printButton = new Button("Print") { - // xAlignment = Alignment.Center - peer.setAlignmentX(0.5f) + // peer.setAlignmentX(0.5f) + xLayoutAlignment = 0.50 // Center } //Add the scroll pane to this panel. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index b988ef08..76543c1d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -440,8 +440,6 @@ class TextComponentDemo extends MainFrame { } object TextComponentDemo extends SimpleSwingApplication { - lazy val top = new TextComponentDemo() { - javax.swing.UIManager.put("swing.boldMetal", false) - } - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) + UIManager.put("swing.boldMetal", false) + lazy val top = new TextComponentDemo() } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BLDComponent.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BLDComponent.scala new file mode 100644 index 00000000..d7720d33 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BLDComponent.scala @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ +import scala.swing.event.MousePressed +import java.awt.{ Color, Dimension, Graphics2D } + +/** + * A rectangle that has a fixed maximum size. + * + * Used by BoxLayoutDemo.scala. + */ +class BLDComponent(alignmentX: Float, hue: Float, shortSideSize: Int, + var restrictMaximumSize: Boolean, val printSize: Boolean, nameArg: String) extends Panel { + name = nameArg + xLayoutAlignment = alignmentX + opaque = true + val normalHue = Color.getHSBColor(hue, 0.4f, 0.85f) + preferredSize = new Dimension(shortSideSize * 2, shortSideSize) + listenTo(mouse.clicks) + + reactions += { + case MousePressed(_, point: Point, _, _, _) => + val alignment = point.getX().toFloat / size.getWidth().toFloat + // Round to the nearest 1/10th. + val tmp = Math.round(alignment * 10.0f) + xLayoutAlignment = tmp.toFloat / 10.0f + revalidate() /// this GUI needs relayout + repaint() + } + + override def paintComponent(g: Graphics2D): Unit = { + super.paintComponent(g) + val width: Int = size.getWidth().toInt + val height: Int = size.getHeight().toInt + val alignmentX: Float = xLayoutAlignment.toFloat + + g.setColor(normalHue); + g.fill3DRect(0, 0, width, height, true); + + /* Draw a vertical white line at the alignment point.*/ + // XXX: This code is probably not the best. + g.setColor(Color.white); + val x: Int = (alignmentX * width.toFloat).toInt - 1; + g.drawLine(x, 0, x, height - 1); + + /* Say what the alignment point is. */ + g.setColor(Color.black); + g.drawString(alignmentX.toString, 3, height - 3); + + if (printSize) { + System.out.println("BLDComponent " + name + ": size is " + + width + "x" + height + + "; preferred size is " + + preferredSize.getWidth() + "x" + + preferredSize.getHeight()); + } + } + + def getMaximumSize(): Dimension = { + if (restrictMaximumSize) preferredSize else super.maximumSize + } + + def setSizeRestriction(restrictSize: Boolean): Unit = { + restrictMaximumSize = restrictSize + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala new file mode 100644 index 00000000..3093bfeb --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ +import javax.swing.{SwingUtilities, UIManager} +import java.awt.{ ComponentOrientation, Dimension } + +/* + * Tutorials: How to Use BorderLayout + * http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BorderLayoutDemoProject/src/layout/BorderLayoutDemo.java + */ +class BorderLayoutDemo extends BorderPanel { + if (BorderLayoutDemo.RightToLeft) { + peer.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) + } + val button1 = new Button("Button 1 (PAGE_START)") + val button2 = new Button("Button 2 (CENTER)") { + preferredSize = new Dimension(200, 100) + } + val button3 = new Button("Button 3 (LINE_START)") + val button4 = new Button("Long-Named Button 4 (PAGE_END)") + val button5 = new Button("5 (LINE_START)") + + layout(button1) = BorderPanel.Position.North + layout(button2) = BorderPanel.Position.Center + layout(button3) = BorderPanel.Position.West + layout(button4) = BorderPanel.Position.East + layout(button5) = BorderPanel.Position.South +} + +object BorderLayoutDemo extends SimpleSwingApplication { + val RightToLeft = false + /* Use an appropriate Look and Feel */ + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") + /* Turn off metal's use bold fonts */ + UIManager.put("swing.boldMetal", false) + //Create and set up the window. + lazy val top = new MainFrame { + title = "BorderLayoutDemo" + contents = new BorderLayoutDemo() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala new file mode 100644 index 00000000..d6cdc3b2 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala @@ -0,0 +1,170 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ +import javax.swing.{ ImageIcon } +import java.awt.{ Color, Dimension } +import java.net.URL + +/* + * Tutorials: How to Use BoxAlignment + * http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxAlignmentDemoProject/src/layout/BoxAlignmentDemo.java + * + * BoxAlignmentDemo.scala requires the following files: + * scala/swing/examples/tutorials/images/middle.gif + * scala/swing/examples/tutorials/images/geek-cght.gif + * + * This demo shows how to specify alignments when you're using + * a BoxLayout for components with maximum sizes and different + * default alignments. + */ +class BoxAlignmentDemo extends BorderPanel { + + val buttonRow = new FlowPanel() { + contents += createButtonRow(false) + contents += createButtonRow(true) + } + val labelAndComponent = new FlowPanel() { + contents += createLabelAndComponent(false) + contents += createLabelAndComponent(true) + } + val buttonAndComponent = new FlowPanel() { + contents += createYAlignmentExample(false) + contents += createYAlignmentExample(true) + } + val tabbedPane = new TabbedPane() + tabbedPane.pages += new TabbedPane.Page("Altering alignments", buttonRow) + tabbedPane.pages += new TabbedPane.Page("X alignment mismatch", labelAndComponent) + tabbedPane.pages += new TabbedPane.Page("Y alignment mismatch", buttonAndComponent) + //Add tabbedPane to this panel + layout(tabbedPane) = BorderPanel.Position.Center + + def createButtonRow(changeAlignment: Boolean): BoxPanel = { + val button1 = new Button("A Button") { + icon = BoxAlignmentDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get + verticalTextPosition = Alignment.Bottom + horizontalTextPosition = Alignment.Center + } + val button2 = new Button("Another Button") { + icon = BoxAlignmentDemo.createImageIcon("/scala/swing/examples/tutorials/images/geek-cght.gif").get + verticalTextPosition = Alignment.Bottom + horizontalTextPosition = Alignment.Center + } + val title = if (changeAlignment) "Desired" else "Default" + if (changeAlignment) { + button1.yLayoutAlignment = 1.0f // Bottom + button2.yLayoutAlignment = 1.0f // Bottom + } + val panel = new BoxPanel(Orientation.Horizontal) { + border = Swing.TitledBorder(Swing.EmptyBorder, title) + contents += button1 + contents += button2 + } + panel + } + + def createLabelAndComponent(doItRight: Boolean): BoxPanel = { + val dSize = new Dimension(150, 100) + val component = new FlowPanel() { + maximumSize = dSize + preferredSize = dSize + minimumSize = dSize + border = Swing.TitledBorder(Swing.LineBorder(Color.black), "A Panel") + } + val title = if (doItRight) "Matched" else "Mismatched" + val paneBorder = Swing.TitledBorder(Swing.EmptyBorder, title) + paneBorder.setTitleJustification(javax.swing.border.TitledBorder.CENTER) + paneBorder.setTitlePosition(javax.swing.border.TitledBorder.BELOW_TOP) + paneBorder.setTitleColor(Color.black) + val label = new Label("This is a Label") + if (doItRight) label.xLayoutAlignment = 0.5f // Center + val pane = new BoxPanel(Orientation.Vertical) { + border = paneBorder + contents += label + contents += component + } + pane + } + + def createYAlignmentExample(doItRight: Boolean): BoxPanel = { + val dSize1 = new Dimension(150, 100) + val title = if (doItRight) "Matched" else "Mismatched" + val componentBorder = Swing.TitledBorder(Swing.LineBorder(Color.black), "A Panel") + componentBorder.setTitleJustification(javax.swing.border.TitledBorder.CENTER) + componentBorder.setTitlePosition(javax.swing.border.TitledBorder.BELOW_TOP) + componentBorder.setTitleColor(Color.black) + val component1 = new FlowPanel() { + maximumSize = dSize1 + preferredSize = dSize1 + minimumSize = dSize1 + border = componentBorder + } + if (!doItRight) component1.yLayoutAlignment = 0.0f // TOP_ALIGNMENT + + val dSize2 = new Dimension(100, 50) + val component2 = new FlowPanel() { + maximumSize = dSize2 + preferredSize = dSize2 + minimumSize = dSize2 + border = componentBorder + } + val paneBorder = Swing.TitledBorder(Swing.EmptyBorder, title) + val pane = new BoxPanel(Orientation.Horizontal) { + border = paneBorder + contents += component1 + contents += component2 + } + pane + } +} + +object BoxAlignmentDemo extends SimpleSwingApplication { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String): Option[ImageIcon] = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Some(new ImageIcon(imgURL)) + } else { + System.err.println("Couldn't find file: " + path) + return None + } + } + + //Create and set up the window. + lazy val top = new MainFrame { + title = "BoxAlignmentDemo" + contents = new BoxAlignmentDemo() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala new file mode 100644 index 00000000..cabdb6da --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ + +/* + * Tutorials: How to Use BoxLayout + * http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemoProject/src/layout/BoxLayoutDemo.java + * + * BoxLayoutDemo.scala requires no other files. + */ +class BoxLayoutDemo extends BoxPanel(Orientation.Vertical) { + val button1 = new Button("Button 1") { + xLayoutAlignment = 0.5 + } + val button2 = new Button("Button 2") { + xLayoutAlignment = 0.5 + } + val button3 = new Button("Button 3") { + xLayoutAlignment = 0.5 + } + val button4 = new Button("Long-Named Button 4") { + xLayoutAlignment = 0.5 + } + val button5 = new Button("5") { + xLayoutAlignment = 0.5 + } + contents += button1 + contents += button2 + contents += button3 + contents += button4 + contents += button5 +} + +object BoxLayoutDemo extends SimpleSwingApplication { + //Create and set up the window. + lazy val top = new MainFrame { + title = "BoxLayoutDemo" + contents = new BoxLayoutDemo() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala new file mode 100644 index 00000000..dd6fa67e --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.Color + +/* + * Tutorials: How to Use BoxLayout + * http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html + * + * Source code references: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemo2Project/src/layout/BoxLayoutDemo2.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemo2Project/src/layout/BLDComponent.java + * + * BoxLayoutDemo2.scala requires BLDComponent.scala. + */ +class BoxLayoutDemo2 extends BorderPanel { + private val NumComponents = 3 + // Component.LEFT_ALIGNMENT, Component.CENTER_ALIGNMENT, Component.RIGHT_ALIGNMENT + private val xAlignment = Array(0.0f, 0.5f, 1.0f) + private val hue = Array(0.0f, 0.33f, 0.67f) + private var restrictSize = true + private val sizeIsRandom = false + private val bldComponent = new Array[BLDComponent](NumComponents) + val panel = new BoxPanel(Orientation.Vertical) + //Create the rectangles. + var shortSideSize = 15 + for (i <- 0 until NumComponents) { + if (sizeIsRandom) { + shortSideSize = (30.0 * Math.random()).toInt + 30 + } + else { + shortSideSize += 10 + } + bldComponent(i) = new BLDComponent(xAlignment(i), hue(i), + shortSideSize, restrictSize, sizeIsRandom, i.toString) + panel.contents += bldComponent(i).asInstanceOf[Component] + } + + //Create the instructions. + val label = new Label("Click a rectangle to change its X alignment.") + val cb = new CheckBox("Restrict maximum rectangle size.") { + selected = restrictSize + } + + border = Swing.LineBorder(Color.red) + + // Use a BoxPanel instead of javax.swing.Box + val box = new BoxPanel(Orientation.Vertical) { + contents += label + contents += cb + } + + layout(panel) = BorderPanel.Position.Center + layout(box) = BorderPanel.Position.South + + listenTo(cb) + + reactions += { + case ButtonClicked(`cb`) => + restrictSize = cb.selected + notifyBldComponents() + } + + def notifyBldComponents(): Unit = { + for (i <- 0 until NumComponents) + bldComponent(i).setSizeRestriction(restrictSize) + bldComponent(0).revalidate + } +} + +object BoxLayoutDemo2 extends SimpleSwingApplication { + lazy val top = new MainFrame() { + title = "BoxLayoutDemo2" + contents = new BoxLayoutDemo2() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala new file mode 100644 index 00000000..a708f43a --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ + +/* + * Tutorials: Creating a Custom Layout Manager + * http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java + * + * CustomLayoutDemo.java requires one other file: + * DiagonalLayout.java + */ +class CustomLayoutDemo() extends Panel with SequentialContainer.Wrapper { + override lazy val peer: javax.swing.JPanel = + new javax.swing.JPanel(new DiagonalLayout()) with SuperMixin + + private def layoutManager = peer.getLayout.asInstanceOf[DiagonalLayout] + + val b1 = new Button("Button 1") + val b2 = new Button("Button 2") + val b3 = new Button("Button 3") + val b4 = new Button("Button 4") + val b5 = new Button("Button 5") + val buttons: Seq[Component] = Seq(b1, b2, b3, b4, b5) + contents ++= buttons +} + +object CustomLayoutDemo extends SimpleSwingApplication { + lazy val top = new MainFrame() { + title = "CustomLayoutDemo" + contents = new CustomLayoutDemo() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala new file mode 100644 index 00000000..45bb7451 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +/* + * 1.2+ version. Used by CustomLayoutDemo.java. + */ + +import java.awt._ +//remove if not needed +import scala.collection.JavaConversions._ + +class DiagonalLayout(private var vgap: Int) extends LayoutManager { + + private var minWidth: Int = 0 + + private var minHeight: Int = 0 + + private var preferredWidth: Int = 0 + + private var preferredHeight: Int = 0 + + private var sizeUnknown: Boolean = true + + def this() { + this(5) + } + + /* Required by LayoutManager. */ + def addLayoutComponent(name: String, comp: Component) { + } + + def removeLayoutComponent(comp: Component) { + } + + private def setSizes(parent: Container) { + val nComps = parent.getComponentCount + var d: Dimension = null + //Reset preferred/minimum width and height. + preferredWidth = 0 + preferredHeight = 0 + minWidth = 0 + minHeight = 0 + for (i <- 0 until nComps) { + val c = parent.getComponent(i) + if (c.isVisible) { + d = c.getPreferredSize + if (i > 0) { + preferredWidth += d.width / 2 + preferredHeight += vgap + } else { + preferredWidth = d.width + } + preferredHeight += d.height + minWidth = Math.max(c.getMinimumSize.width, minWidth) + minHeight = preferredHeight + } + } + } + + /* Required by LayoutManager. */ + def preferredLayoutSize(parent: Container): Dimension = { + val dim = new Dimension(0, 0) + val nComps = parent.getComponentCount + setSizes(parent) + val insets = parent.getInsets + dim.width = preferredWidth + insets.left + insets.right + dim.height = preferredHeight + insets.top + insets.bottom + sizeUnknown = false + dim + } + + /* Required by LayoutManager. */ + def minimumLayoutSize(parent: Container): Dimension = { + val dim = new Dimension(0, 0) + val nComps = parent.getComponentCount + val insets = parent.getInsets + dim.width = minWidth + insets.left + insets.right + dim.height = minHeight + insets.top + insets.bottom + sizeUnknown = false + dim + } + + /* Required by LayoutManager. */ + /* + * This is called when the panel is first displayed, + * and every time its size changes. + * Note: You CAN'T assume preferredLayoutSize or + * minimumLayoutSize will be called -- in the case + * of applets, at least, they probably won't be. + */ + def layoutContainer(parent: Container) { + val insets = parent.getInsets + val maxWidth = parent.getWidth - (insets.left + insets.right) + val maxHeight = parent.getHeight - (insets.top + insets.bottom) + val nComps = parent.getComponentCount + var previousWidth = 0 + var previousHeight = 0 + var x = 0 + var y = insets.top + val rowh = 0 + val start = 0 + var xFudge = 0 + var yFudge = 0 + var oneColumn = false + // Go through the components' sizes, if neither + // preferredLayoutSize nor minimumLayoutSize has + // been called. + if (sizeUnknown) { + setSizes(parent) + } + if (maxWidth <= minWidth) { + oneColumn = true + } + if (maxWidth != preferredWidth) { + xFudge = (maxWidth - preferredWidth) / (nComps - 1) + } + if (maxHeight > preferredHeight) { + yFudge = (maxHeight - preferredHeight) / (nComps - 1) + } + for (i <- 0 until nComps) { + val c = parent.getComponent(i) + if (c.isVisible) { + val d = c.getPreferredSize + // increase x and y, if appropriate + if (i > 0) { + if (!oneColumn) { + x += previousWidth / 2 + xFudge + } + y += previousHeight + vgap + yFudge + } + // If x is too large, + if ((!oneColumn) && (x + d.width) > (parent.getWidth - insets.right)) { + x = parent.getWidth - insets.bottom - d.width + } + // If y is too large, + if ((y + d.height) > (parent.getHeight - insets.bottom)) { + // do nothing. + // Another choice would be to do what we do to x. + } + // Set the component's size and position. + c.setBounds(x, y, d.width, d.height) + previousWidth = d.width + previousHeight = d.height + } + } + } + + override def toString(): String = { + val str = "" + getClass.getName + "[vgap=" + vgap + str + "]" + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala new file mode 100644 index 00000000..47708fcf --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ +import javax.swing.UIManager + +/* + * Tutorials: Creating a Custom Layout Manager + * http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html + * + * Source code reference: + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java + * + * CustomLayoutDemo.java requires one other file: + * DiagonalLayout.java + */ +class FlowLayoutDemo() extends FlowPanel { + +} + +object FlowLayoutDemo extends SimpleSwingApplication { + /* Use an appropriate Look and Feel */ + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") + /* Turn off metal's use of bold fonts */ + UIManager.put("swing.boldMetal", false) + lazy val top = new MainFrame() { + title = "FlowLayoutDemo" + contents = new FlowLayoutDemo() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala index 4e448ed7..61cf1150 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala @@ -32,6 +32,7 @@ package scala.swing.examples.tutorials.misc import scala.swing._ import scala.util.control.NonFatal +import javax.swing.UIManager /* * Tutorial: How to Use the Focus System @@ -91,16 +92,15 @@ object FocusConceptsDemo extends SimpleSwingApplication { try { //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); - javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); } catch { case NonFatal(ex) => ex.printStackTrace() } /* Turn off metal's use of bold fonts */ - javax.swing.UIManager.put("swing.boldMetal", false); + UIManager.put("swing.boldMetal", false); //Create and set up the window. lazy val top = new MainFrame() { title = "FocusConceptsDemo" contents = new FocusConceptsDemo() } - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file From 222558e0abc00a0bcb7553507f6975da54b9e6d7 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Tue, 30 Sep 2014 19:22:15 -0700 Subject: [PATCH 25/36] Simplify createImageIcon so that it uses a map instead of an if-then-else. --- .../tutorials/components/ButtonDemo.scala | 19 +++++++------------ .../tutorials/components/ButtonHtmlDemo.scala | 19 ++++++------------- .../tutorials/components/CheckboxDemo.scala | 9 ++------- .../tutorials/components/ComboBoxDemo.scala | 9 ++------- .../components/CustomComboBoxDemo.scala | 9 ++------- .../tutorials/components/DialogDemo.scala | 9 ++------- .../tutorials/components/IconDemoApp.scala | 12 +++--------- .../tutorials/components/LabelDemo.scala | 11 +++-------- .../tutorials/components/MenuDemo.scala | 9 ++------- .../tutorials/components/MenuLookDemo.scala | 9 ++------- .../tutorials/components/PopupMenuDemo.scala | 9 ++------- .../components/RadioButtonDemo.scala | 9 ++------- .../tutorials/components/ScrollDemo.scala | 10 ++-------- .../tutorials/components/SliderDemo.scala | 16 +++++----------- .../tutorials/components/SliderDemo2.scala | 12 +++--------- .../tutorials/components/SplitPaneDemo.scala | 10 ++-------- .../components/SplitPaneDividerDemo.scala | 10 ++-------- .../tutorials/components/TabbedPaneDemo.scala | 10 ++-------- .../components/TextSamplerDemo.scala | 9 ++------- .../tutorials/layout/BoxAlignmentDemo.scala | 10 ++-------- 20 files changed, 55 insertions(+), 165 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala index 8e2dab03..2a429f25 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala @@ -47,9 +47,9 @@ import javax.swing.UIManager * /scala/swing/examples/tutorials/images/left.gif */ class ButtonDemo extends FlowPanel { - val leftButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get - val middleButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val rightButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get + val leftButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get + val middleButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get + val rightButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get // val disable: Button = new Button("Disable middle button") { icon = leftButtonIcon @@ -96,19 +96,14 @@ class ButtonDemo extends FlowPanel { middle.enabled = false disable.enabled = false } - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - val imgURL: java.net.URL = getClass().getResource(path) - val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } - img - } + } object ButtonDemo extends SimpleSwingApplication { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + } UIManager.put("swing.boldMetal", false) lazy val top = new MainFrame() { title = "ButtonDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala index 2a817f46..43f367ae 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -47,9 +47,9 @@ import java.awt.Font * /scala/swing/examples/tutorials/images/left.gif */ class ButtonHtmlDemo extends FlowPanel { - val leftButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get - val middleButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val rightButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get + val leftButtonIcon = ButtonHtmlDemo.createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get + val middleButtonIcon = ButtonHtmlDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get + val rightButtonIcon = ButtonHtmlDemo.createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get // val disable: Button = new Button("

Disable
" + "middle button") { @@ -102,19 +102,12 @@ class ButtonHtmlDemo extends FlowPanel { middle.enabled = false disable.enabled = false } - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - val imgURL: java.net.URL = getClass().getResource(path) - val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } - img - } - } object ButtonHtmlDemo extends SimpleSwingApplication { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + } lazy val top = new MainFrame() { title = "ButtonHtmlDemo" //Create and set up the content pane. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index 80026a16..c72c8d81 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -159,13 +159,8 @@ class CheckboxDemo extends BorderPanel { object CheckboxDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { title = "CheckboxDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index 458bddab..25b3a900 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -91,13 +91,8 @@ object ComboBoxDemo extends SimpleSwingApplication { val pigString = "Pig" /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { title = "ComboBoxDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index e50e9e5f..c6f13a24 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -121,13 +121,8 @@ class CustomComboBoxDemo extends BorderPanel { object CustomComboBoxDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index 5f90479b..8501234f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -485,13 +485,8 @@ class DialogDemo(val frame: Frame) extends BorderPanel { object DialogDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index 2dc47f8b..71b141fa 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -182,15 +182,9 @@ class IconDemoApp extends MainFrame { } object IconDemoApp extends SimpleSwingApplication { - def createImageIcon(path: String, - description: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(new ImageIcon(imgURL, description)) - } else { - System.err.println("Couldn't find file: " + path); - None - } + def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { + val icon = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + if (icon.isDefined) { icon.get.setDescription(description); icon } else None } lazy val top = new IconDemoApp() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index b6d16044..d799d516 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -71,14 +71,9 @@ class LabelDemo extends GridPanel(3, 1) { object LabelDemo extends SimpleSwingApplication { UIManager.put("swing.boldMetal", false) /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String, description: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description. - Some(new ImageIcon(imgURL, description)) - } else { - None - } + def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { + val icon = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + if (icon.isDefined) { icon.get.setDescription(description); icon } else None } lazy val top = new MainFrame() { title = "LabelDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index 78fc113c..0e3a40d9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -201,13 +201,8 @@ class MenuDemo extends BorderPanel { object MenuDemo extends SimpleSwingApplication { /** Returns an ImageIcon icon, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { title = "MenuDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala index 5b6f81fc..611299e9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -171,13 +171,8 @@ class MenuLookDemo extends BorderPanel { object MenuLookDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala index d635e0ee..5a390b4e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -237,13 +237,8 @@ class PopupMenuDemo extends BorderPanel { object PopupMenuDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } /** * Create the GUI and show it. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index 99749ba3..276b5943 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -133,13 +133,8 @@ object RadioButtonDemo extends SimpleSwingApplication { val pigString = "Pig" /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { title = "RadioButtonDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala index a1eb43ca..f61bc304 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -119,14 +119,8 @@ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { object ScrollDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description in the peer. - Some(new ImageIcon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index 721d7590..0f9facf0 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -155,9 +155,9 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act def updatePicture(frameNum: Int): Unit = { //Get the image if we haven't already. if (images(frameNumber) == null) { - images(frameNumber) = SliderDemo.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" - + frameNumber - + ".gif"); + images(frameNumber) = SliderDemo.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" + + frameNumber + + ".gif").get; } //Set the image. @@ -172,14 +172,8 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act object SliderDemo extends SimpleSwingApplication { UIManager.put("swing.boldMetal", false) /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): ImageIcon = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description. - new javax.swing.ImageIcon(imgURL) - } else { - null - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 6714f229..0d215bca 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -170,16 +170,10 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { object SliderDemo2 extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description in the peer. - Some(new ImageIcon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } - + lazy val top = new MainFrame() { title = "SliderDemo2" javax.swing.UIManager.put("swing.boldMetal", false) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index a133732b..0d074232 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -101,14 +101,8 @@ class SplitPaneDemo extends FlowPanel { object SplitPaneDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or NOne if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description. - Some(new ImageIcon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index 18141a7a..34fcc76d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -88,14 +88,8 @@ class SplitPaneDividerDemo extends BorderPanel { object SplitPaneDividerDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description. - Some(new ImageIcon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala index ce8e24f9..012020c7 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala @@ -81,14 +81,8 @@ class TabbedPaneDemo extends GridPanel(1, 1) { object TabbedPaneDemo extends SimpleSwingApplication { /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - // scala swing has no mechanism for setting the description. - Some(new ImageIcon(imgURL)) - } else { - None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala index 7747bbf1..01b94871 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -286,13 +286,8 @@ object TextSamplerDemo extends SimpleSwingApplication { } private def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { - val imgURL: java.net.URL = getClass().getResource(path) - val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { - Some(new javax.swing.ImageIcon(imgURL, description)) - } else { - None - } - img + val icon = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + if (icon.isDefined) { icon.get.setDescription(description); icon } else None } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala index d6cdc3b2..c879b97a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala @@ -152,14 +152,8 @@ class BoxAlignmentDemo extends BorderPanel { object BoxAlignmentDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(new ImageIcon(imgURL)) - } else { - System.err.println("Couldn't find file: " + path) - return None - } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } //Create and set up the window. From 81a336107dc1511706c5b84a315971487cef18a7 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Tue, 30 Sep 2014 19:32:49 -0700 Subject: [PATCH 26/36] Remove a reference to the ComboBox peer to set editable to true. This can be done using the function makeEditable. --- .../swing/examples/tutorials/components/ComboBoxDemo2.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala index 6198cdf3..07a5f82c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -62,8 +62,7 @@ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { val patternLabel1 = new Label("Enter the pattern string or") val patternLabel2 = new Label("select one from the list:") val patternList = new ComboBox[String](patternExamples) { - peer.setEditable(true) - // editable = true + makeEditable() selection.item = patternExamples(0) xLayoutAlignment = 0.0 // Left } From f0ea41e6c515c6ba695f28817217361a7158ff4b Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Tue, 30 Sep 2014 20:17:12 -0700 Subject: [PATCH 27/36] Scaladoc changes to files using BorderDemo as a template. Replacement of stray references to java files with references to scala files. --- .../examples/tutorials/components/ButtonDemo.scala | 6 +++--- .../tutorials/components/ButtonHtmlDemo.scala | 6 +++--- .../examples/tutorials/components/CheckboxDemo.scala | 6 +++--- .../tutorials/components/ColorChooserDemo.scala | 9 +++++---- .../examples/tutorials/components/ComboBoxDemo.scala | 6 +++--- .../tutorials/components/ComboBoxDemo2.scala | 9 +++++---- .../tutorials/components/CustomComboBoxDemo.scala | 6 +++--- .../examples/tutorials/components/DialogDemo.scala | 6 +++--- .../tutorials/components/DocumentSizeFilter.scala | 2 +- .../tutorials/components/FileChooserDemo.scala | 6 +++--- .../components/FormattedTextFieldDemo.scala | 6 +++--- .../examples/tutorials/components/FrameDemo.scala | 6 +++--- .../examples/tutorials/components/FrameDemo2.scala | 6 +++--- .../examples/tutorials/components/HtmlDemo.scala | 8 ++++---- .../examples/tutorials/components/IconDemoApp.scala | 8 ++++---- .../examples/tutorials/components/LabelDemo.scala | 7 ++++--- .../examples/tutorials/components/ListDemo.scala | 7 ++++--- .../examples/tutorials/components/ListDialog.scala | 8 ++++---- .../tutorials/components/ListDialogRunner.scala | 9 ++++----- .../examples/tutorials/components/MenuDemo.scala | 6 +++--- .../examples/tutorials/components/MenuGlueDemo.scala | 6 +++--- .../examples/tutorials/components/MenuLookDemo.scala | 6 +++--- .../examples/tutorials/components/PasswordDemo.scala | 6 +++--- .../tutorials/components/PopupMenuDemo.scala | 6 +++--- .../tutorials/components/RadioButtonDemo.scala | 6 +++--- .../examples/tutorials/components/ScrollDemo.scala | 12 ++++++------ .../examples/tutorials/components/ScrollDemo2.scala | 6 +++--- .../tutorials/components/SimpleTableDemo.scala | 4 ++-- .../components/SimpleTableSelectionDemo.scala | 7 ++++--- .../examples/tutorials/components/SliderDemo.scala | 6 +++--- .../examples/tutorials/components/SliderDemo2.scala | 6 +++--- .../tutorials/components/SplitPaneDemo.scala | 6 +++--- .../tutorials/components/SplitPaneDemo2.scala | 6 +++--- .../tutorials/components/SplitPaneDividerDemo.scala | 8 ++++---- .../tutorials/components/TabbedPaneDemo.scala | 6 +++--- .../examples/tutorials/components/TableDemo.scala | 6 +++--- .../tutorials/components/TableFTFEditDemo.scala | 10 +++++----- .../tutorials/components/TablePrintDemo.scala | 6 +++--- .../tutorials/components/TableSelectionDemo.scala | 6 +++--- .../tutorials/components/TextComponentDemo.scala | 10 +++++----- .../examples/tutorials/components/TextDemo.scala | 8 ++++---- .../tutorials/components/TextSamplerDemo.scala | 8 ++++---- .../examples/tutorials/components/TopLevelDemo.scala | 6 +++--- .../examples/tutorials/components/TumbleItem.scala | 6 +++--- .../examples/tutorials/concurrency/Flipper.scala | 6 +++--- .../examples/tutorials/layout/BorderLayoutDemo.scala | 6 +++--- .../examples/tutorials/layout/BoxAlignmentDemo.scala | 6 +++--- .../examples/tutorials/layout/BoxLayoutDemo.scala | 6 +++--- .../examples/tutorials/layout/BoxLayoutDemo2.scala | 8 ++++---- .../examples/tutorials/layout/CustomLayoutDemo.scala | 12 ++++++------ .../examples/tutorials/layout/DiagonalLayout.scala | 2 +- .../examples/tutorials/layout/FlowLayoutDemo.scala | 12 ++++++------ .../swing/examples/tutorials/misc/ActionDemo.scala | 8 ++++---- .../examples/tutorials/misc/FocusConceptsDemo.scala | 6 +++--- 54 files changed, 186 insertions(+), 182 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala index 2a429f25..5f0f8ca8 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala @@ -34,12 +34,12 @@ import scala.swing._ import scala.swing.event.ButtonClicked import javax.swing.UIManager -/* +/** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ButtonDemoProject/src/components/ButtonDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ButtonDemoProject/src/components/ButtonDemo.java]] * * ButtonDemo.scala requires the following files: * /scala/swing/examples/tutorials/images/right.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala index 43f367ae..1e3a4444 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -34,12 +34,12 @@ import scala.swing._ import scala.swing.event.ButtonClicked import java.awt.Font -/* +/** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ButtonHtmlDemoProject/src/components/ButtonHtmlDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ButtonHtmlDemoProject/src/components/ButtonHtmlDemo.java]] * * ButtonHtmlDemo.scala requires the following files: * /scala/swing/examples/tutorials/images/right.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index c72c8d81..4a56a178 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -37,12 +37,12 @@ import java.awt.Font import javax.swing.ImageIcon import java.net.URL -/* +/** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CheckBoxDemoProject/src/components/CheckBoxDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CheckBoxDemoProject/src/components/CheckBoxDemo.java]] * * CheckBoxDemo.scala requires 16 image files in the /scala/swing/examples/tutorials/images/geek * directory: diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala index 59ef6ffd..fbf74bec 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala @@ -35,14 +35,15 @@ import scala.swing.Swing.EmptyIcon import scala.swing.event.ColorChanged import java.awt.{ Color, Dimension, Font } -/* +/** * Tutorial: How to Use Color Choosers - * http://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ColorChooserDemoProject/src/components/ColorChooserDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ColorChooserDemoProject/src/components/ColorChooserDemo.java]] + * + * ColorChooserDemo.scala requires no other files. */ -/* ColorChooserDemo.java requires no other files. */ class ColorChooserDemo extends BorderPanel { //Set up the banner at the top of the window val banner = new Label("Welcome to the Tutorial Zone!", EmptyIcon, Alignment.Center) { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index 25b3a900..ac4b0744 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -37,12 +37,12 @@ import java.awt.{ Dimension, Font } import javax.swing.{ BorderFactory, ImageIcon } import java.net.URL -/* +/** * Tutorial: How to Use Combo Boxes - * http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemoProject/src/components/ComboBoxDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemoProject/src/components/ComboBoxDemo.java]] */ class ComboBoxDemo extends BorderPanel { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala index 07a5f82c..6fd3f393 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -37,14 +37,15 @@ import java.awt.Color import java.util.Date import java.text.SimpleDateFormat -/* +/** * Tutorial: How to Use Combo Boxes - * http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemo2Project/src/components/ComboBoxDemo2.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemo2Project/src/components/ComboBoxDemo2.java]] + * + * ComboBoxDemo2.scala requires no other files. */ -/* ComboBoxDemo2.java requires no other files. */ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { val patternExamples = Array[String]( "dd MMMMM yyyy", diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index c6f13a24..48b685cb 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -36,12 +36,12 @@ import javax.swing.ImageIcon import java.net.URL import java.awt.{ Dimension, Font } -/* +/** * Tutorial: How to Use Combo Boxes - * http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CustomComboBoxDemoProject/src/components/CustomComboBoxDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CustomComboBoxDemoProject/src/components/CustomComboBoxDemo.java]] * * CustomComboBoxDemo.scala uses the following files: * /scala/swing/examples/tutorials/images/Bird.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index 8501234f..0e31ba60 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -38,12 +38,12 @@ import java.net.URL import javax.swing.ImageIcon import java.awt.{ Dimension, Font } -/* +/** * Tutorial: How to Use Dialogs - * http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/DialogDemoProject/src/components/DialogDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/DialogDemoProject/src/components/DialogDemo.java]] * * DialogDemo.scala requires these files: * CustomDialog.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala index 9a450af4..157d6e6e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala @@ -34,7 +34,7 @@ package scala.swing.examples.tutorials.components import java.awt.Toolkit import javax.swing.text.{ AttributeSet, DocumentFilter } -/* A 1.4 class used by TextComponentDemo.java. */ +/* A 1.4 class used by TextComponentDemo.scala. */ class DocumentSizeFilter(val maxCharacters: Int) extends DocumentFilter { val Debug: Boolean = false diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala index 8e346743..d8ecc216 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala @@ -36,12 +36,12 @@ import scala.swing.event._ import java.io.File import java.net.URL -/* +/** * Tutorial: How to Use File Choosers - * http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FileChooserDemoProject/src/components/FileChooserDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FileChooserDemoProject/src/components/FileChooserDemo.java]] * * FileChooserDemo.scala uses these files: * /scala/swing/examples/tutorials/images/Open16.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala index 93cc2f28..5674e58f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala @@ -35,12 +35,12 @@ import java.text.NumberFormat import java.awt.Color import javax.swing.UIManager -/* +/** * Tutorial: How to Use Formatted Text Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FormattedTextFieldDemoProject/src/components/FormattedTextFieldDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FormattedTextFieldDemoProject/src/components/FormattedTextFieldDemo.java]] * * FormattedTextFieldDemo.scala requires no other files. * diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala index 6f6f79ff..b0d5ff89 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo.scala @@ -33,12 +33,12 @@ package scala.swing.examples.tutorials.components import scala.swing._ import java.awt.Dimension -/* +/** * Tutorial: How to Make Frames (Main Windows) - * http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemoProject/src/components/FrameDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemoProject/src/components/FrameDemo.java]] * * FrameDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index 18a89a83..a47ec307 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -37,12 +37,12 @@ import java.awt.{ BorderLayout, Color, Component, Dimension, Graphics, Image, Po import java.awt.image.BufferedImage import java.net.URL -/* +/** * Tutorial: How to Make Frames (Main Windows) - * http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemo2Project/src/components/FrameDemo2.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemo2Project/src/components/FrameDemo2.java]] * * FrameDemo2.scala shows off the window decoration features added in * 1.4, plus some window positioning code and (optionally) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala index 84db4d65..5a97cc83 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala @@ -35,14 +35,14 @@ import scala.swing.event.ButtonClicked import java.awt.{ Component, Dimension } import scala.swing.event.Key -/* +/** * Tutorial: How to Use HTML in Swing Components - * http://docs.oracle.com/javase/tutorial/uiswing/components/html.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/html.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/HtmlDemoProject/src/components/HtmlDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/HtmlDemoProject/src/components/HtmlDemo.java]] * - * HtmlDemo.java needs no other files. + * HtmlDemo.scala needs no other files. */ class HtmlDemo extends BoxPanel(Orientation.Horizontal) { val initialText = "\n" + diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index 71b141fa..914c9583 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -36,13 +36,13 @@ import java.awt.RenderingHints import java.awt.image.BufferedImage import javax.swing.{ Icon, ImageIcon, JToolBar, SwingWorker } -/* +/** * Tutorial: How to Use Icons - * http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/IconDemoApp.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/MissingIcon.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/IconDemoApp.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/MissingIcon.java]] * * IconDemoApp.scala * MissingIcon.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index d799d516..5fd5d1e1 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -34,12 +34,13 @@ import scala.swing._ import javax.swing.ImageIcon import java.net.URL import javax.swing.UIManager -/* + +/** * Tutorial: How to Use Labels - * http://docs.oracle.com/javase/tutorial/uiswing/components/label.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/label.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/LabelDemoProject/src/components/LabelDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/LabelDemoProject/src/components/LabelDemo.java]] * * LabelDemo.scala needs one other file: * /scala/swing/examples/tutorials/images/middle.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala index 14f38cdb..53dff67d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala @@ -34,12 +34,13 @@ package scala.swing.examples.tutorials.components import scala.swing._ import scala.swing.event.{ ButtonClicked, EditDone, SelectionChanged, ValueChanged } import java.awt.Toolkit -/* + +/** * Tutorial: How to Use Lists - * http://docs.oracle.com/javase/tutorial/uiswing/components/list.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/list.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDemoProject/src/components/ListDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDemoProject/src/components/ListDemo.java]] * * ListDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala index 5ff206fa..8e40c66d 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala @@ -33,13 +33,13 @@ import java.awt.{Dimension, GraphicsConfiguration, Point} import scala.swing._ import scala.swing.event.{ButtonClicked, Key, MouseClicked} -/* +/** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java]] */ /** * Use this modal dialog to let the user choose one string from a long diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala index c72d580f..09ffe4f2 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala @@ -35,15 +35,14 @@ import java.awt.GraphicsEnvironment import scala.swing._ import scala.swing.event.ButtonClicked -/* +/** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java]] */ - class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) { val names: Array[String] = Array("Arlo", "Cosmo", "Elmo", "Hugo", "Jethro", "Laszlo", "Milo", "Nemo", diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index 0e3a40d9..c056df2f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -36,12 +36,12 @@ import java.net.URL import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } -/* +/** * Tutorial: How to Use Menus - * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java]] * * MenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. * diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala index 227a7f51..4f2a222a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala @@ -33,12 +33,12 @@ package scala.swing.examples.tutorials.components import scala.swing._ -/* +/** * Tutorial: How to Use Menus - * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuGlueDemoProject/src/components/MenuGlueDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuGlueDemoProject/src/components/MenuGlueDemo.java]] * * MenuGlueDemo.scala requires no other files. * diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala index 611299e9..ed0b0524 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -36,12 +36,12 @@ import java.net.URL import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } -/* +/** * Tutorial: How to Use Menus - * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuLookDemoProject/src/components/MenuLookDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuLookDemoProject/src/components/MenuLookDemo.java]] * * MenuLookDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. * diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala index 0b652e46..43db934b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala @@ -2,12 +2,12 @@ package scala.swing.examples.tutorials.components import scala.swing._ -/* +/** * Tutorial: How to Use Password Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PasswordDemoProject/src/components/PasswordDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PasswordDemoProject/src/components/PasswordDemo.java]] * * PasswordDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala index 5a390b4e..e1b0740b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -38,12 +38,12 @@ import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } import java.awt.Point -/* +/** * Tutorial: How to Use Password Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PopupMenuDemoProject/src/components/PopupMenuDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PopupMenuDemoProject/src/components/PopupMenuDemo.java]] * * PopupMenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. * diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index 276b5943..275abe13 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -37,12 +37,12 @@ import scala.swing.event.{ ButtonClicked, Key } import javax.swing.ImageIcon import java.net.URL -/* +/** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/RadioButtonDemoProject/src/components/RadioButtonDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/RadioButtonDemoProject/src/components/RadioButtonDemo.java]] * * RadioButtonDemo.scala requires these files: * /scala/swing/examples/tutorials/images/Bird.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala index f61bc304..f36aa935 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -37,15 +37,15 @@ import java.awt.{ Color, Dimension, Font } import java.net.URL import scala.swing.event.ButtonClicked -/* +/** * Tutorial: How to Use Scroll Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Rule.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Corner.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollablePicture.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollDemo.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Rule.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Corner.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollablePicture.java]] * * ScrollDemo.scala requires these files: * Rule.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala index e01f4f0c..1362ef13 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala @@ -36,12 +36,12 @@ import scala.swing.event.MouseReleased import javax.swing.SwingUtilities import java.awt.{Color, Dimension, Graphics2D, Rectangle} -/* +/** * Tutorial: How to Use Scroll Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemo2Project/src/components/ScrollDemo2.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemo2Project/src/components/ScrollDemo2.java]] * * ScrollDemo2.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala index ca262085..af5d0827 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala @@ -35,10 +35,10 @@ import scala.swing.event.MouseClicked import scala.swing.event.MouseClicked /* * Tutorial: How to Use Tables - * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java]] * * SimpleTableDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala index 5fa5cdb6..892a1d1b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala @@ -34,12 +34,13 @@ package scala.swing.examples.tutorials.components import scala.swing._ import scala.collection.immutable.Range import scala.swing.event.{ MouseClicked, TableColumnsSelected, TableRowsSelected } -/* + +/** * Tutorial: How to Use Tables - * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableSelectionDemoProject/src/components/SimpleTableSelectionDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableSelectionDemoProject/src/components/SimpleTableSelectionDemo.java]] * * SimpleTableSelectionDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index 0f9facf0..36fe76b0 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -39,12 +39,12 @@ import javax.swing.Timer import java.net.URL import javax.swing.{ImageIcon, UIManager} -/* +/** * Tutorial: How to Use Sliders - * http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemoProject/src/components/SliderDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemoProject/src/components/SliderDemo.java]] * * SliderDemo.scala requires all the files in the /scala/swing/examples/tutorials/images/doggy * directory. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 0d215bca..491ff4bf 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -39,12 +39,12 @@ import java.net.URL import javax.swing.ImageIcon import scala.collection.mutable.HashMap -/* +/** * Tutorial: How to Use Sliders - * http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemo2Project/src/components/SliderDemo2.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemo2Project/src/components/SliderDemo2.java]] * * SliderDemo2.scala requires all the files in the /scala/swing/examples/tutorials/images/doggy * directory. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index 0d074232..2b9f19a2 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -37,12 +37,12 @@ import java.awt.Font import java.net.URL import javax.swing.ImageIcon -/* +/** * Tutorial: How to Use Split Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemoProject/src/components/SplitPaneDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemoProject/src/components/SplitPaneDemo.java]] */ //SplitPaneDemo itself is not a visible component. class SplitPaneDemo extends FlowPanel { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala index edde1138..d6858335 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -36,12 +36,12 @@ import scala.swing.event.SelectionChanged import java.net.URL import javax.swing.ImageIcon -/* +/** * How to Use Split Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemo2Project/src/components/SplitPaneDemo2.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemo2Project/src/components/SplitPaneDemo2.java]] */ class SplitPaneDemo2 extends MainFrame { title = "SplitPaneDemo2" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index 34fcc76d..3e101a1a 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -37,13 +37,13 @@ import java.awt.Font import java.net.URL import javax.swing.ImageIcon -/* +/** * How to Use Split Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SplitPaneDividerDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SizeDisplayer.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SplitPaneDividerDemo.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SizeDisplayer.java]] * * SplitPaneDividerDemo.scala requires the following files: * SizeDisplayer.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala index 012020c7..dd75fb76 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala @@ -35,12 +35,12 @@ import scala.swing._ import java.net.URL import javax.swing.ImageIcon -/* +/** * How to Use Split Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabbedPaneDemoProject/src/components/TabbedPaneDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabbedPaneDemoProject/src/components/TabbedPaneDemo.java]] * * TabbedPaneDemo.scala requires one additional file: * /scala/swing/examples/tutorials/images/middle.gif. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala index 40153862..4f7eee5f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala @@ -34,12 +34,12 @@ import scala.swing._ import scala.swing.event.MouseClicked import javax.swing.table.DefaultTableModel -/* +/** * Tutorial: How to Use Tables - * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableDemoProject/src/components/TableDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableDemoProject/src/components/TableDemo.java]] * * TableDemo.scala requires no other files. * diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala index 3f7de552..cb1ba4d5 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala @@ -34,16 +34,16 @@ package scala.swing.examples.tutorials.components import scala.swing._ import javax.swing.table.DefaultTableModel -/* +/** * Tutorial: How to Use Tables - * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/TableFTFEditDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/IntegerEditor.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/TableFTFEditDemo.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/IntegerEditor.java]] * * TableFTFEditDemo.scala requires one other file: - * IntegerEditor.java + * IntegerEditor.scala * * This is exactly like TableDemo, except that it uses a * custom cell editor to validate integer input. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala index 0134acad..9e0a2b89 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala @@ -35,12 +35,12 @@ import scala.swing.event.ButtonClicked import javax.swing.table.DefaultTableModel import java.text.MessageFormat -/* +/** * Tutorial: How to Use Tables - * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TablePrintDemoProject/src/components/TablePrintDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TablePrintDemoProject/src/components/TablePrintDemo.java]] * * TablePrintDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala index 901732f1..1687e1cd 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala @@ -37,12 +37,12 @@ import scala.swing.event.ButtonClicked import javax.swing.event.{ListSelectionEvent, ListSelectionListener} import javax.swing.table.DefaultTableModel -/* +/** * Tutorial: How to Use Tables - * http://docs.oracle.com/javase/tutorial/uiswing/components/table.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSelectionDemoProject/src/components/TableSelectionDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSelectionDemoProject/src/components/TableSelectionDemo.java]] * * TableSelectionDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala index 76543c1d..1e76925c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala @@ -41,15 +41,15 @@ import javax.swing.event.{ DocumentEvent, DocumentListener, UndoableEditEvent, U import javax.swing.text.{ AbstractDocument, BadLocationException, DefaultEditorKit, Document, SimpleAttributeSet, StyleConstants, StyledDocument, StyledEditorKit } import javax.swing.undo.UndoManager -/* +/** * Tutorials: How to Use Text Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html]] * How to Use Actions - * http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/DocumentSizeFilter.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/DocumentSizeFilter.java]] * * TextComponentDemo.scala requires one additional file: * DocumentSizeFilter.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala index cb8b21a0..14649ae5 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala @@ -33,14 +33,14 @@ package scala.swing.examples.tutorials.components import scala.swing._ import scala.swing.event.EditDone -/* +/** * Tutorials: How to Use Text Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html]] * How to Use Text Areas - * http://docs.oracle.com/javase/tutorial/uiswing/components/textarea.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/textarea.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextDemoProject/src/components/TextDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextDemoProject/src/components/TextDemo.java]] * * TextDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala index 01b94871..e9d2cb06 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala @@ -37,14 +37,14 @@ import java.awt.{ Cursor, Font, Toolkit } import java.net.URL import javax.swing.text.{ StyleConstants, StyleContext } -/* +/** * Tutorials: How to Use Text Components - * http://docs.oracle.com/javase/tutorial/uiswing/components/text.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/text.html]] * How to Use Editor Panes and Text Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextSamplerDemoProject/src/components/TextSamplerDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextSamplerDemoProject/src/components/TextSamplerDemo.java]] * * TextSamplerDemo.scala requires the following files: * TextSamplerDemoHelp.html (which references images/dukeWaveRed.gif) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala index 9650acc2..010588a0 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TopLevelDemo.scala @@ -32,12 +32,12 @@ package scala.swing.examples.tutorials.components import scala.swing._ -/* +/** * Tutorial: Using Top-Level Containers - * http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TopLevelDemoProject/src/components/TopLevelDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TopLevelDemoProject/src/components/TopLevelDemo.java]] * * TopLevelDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala index 2c35b7b8..df7a3b06 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala @@ -36,12 +36,12 @@ import java.awt.event.{ ActionEvent, ActionListener } import java.awt.{ Color, Graphics, Graphics2D, Toolkit } import javax.swing.{ ImageIcon, SwingUtilities, SwingWorker, Timer } -/* +/** * Tutorial: How to Make Applets - * http://docs.oracle.com/javase/tutorial/uiswing/components/applet.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/components/applet.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TumbleItemProject/src/components/TumbleItem.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TumbleItemProject/src/components/TumbleItem.java]] * * @author jag * @author mem diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala index 6a3327ae..3d3418f6 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/concurrency/Flipper.scala @@ -35,12 +35,12 @@ import scala.swing.event.ButtonClicked import javax.swing.SwingWorker import java.util.Random -/* +/** * Tutorial: Tasks that Have Interim Results - * http://http://docs.oracle.com/javase/tutorial/uiswing/concurrency/interim.html + * [[http://http://docs.oracle.com/javase/tutorial/uiswing/concurrency/interim.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java]] */ class Flipper extends MainFrame { var flipTask: FlipTask = null diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala index 3093bfeb..a2ad0c93 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala @@ -34,12 +34,12 @@ import scala.swing._ import javax.swing.{SwingUtilities, UIManager} import java.awt.{ ComponentOrientation, Dimension } -/* +/** * Tutorials: How to Use BorderLayout - * http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BorderLayoutDemoProject/src/layout/BorderLayoutDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BorderLayoutDemoProject/src/layout/BorderLayoutDemo.java]] */ class BorderLayoutDemo extends BorderPanel { if (BorderLayoutDemo.RightToLeft) { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala index c879b97a..8eab1ee5 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxAlignmentDemo.scala @@ -35,12 +35,12 @@ import javax.swing.{ ImageIcon } import java.awt.{ Color, Dimension } import java.net.URL -/* +/** * Tutorials: How to Use BoxAlignment - * http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxAlignmentDemoProject/src/layout/BoxAlignmentDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxAlignmentDemoProject/src/layout/BoxAlignmentDemo.java]] * * BoxAlignmentDemo.scala requires the following files: * scala/swing/examples/tutorials/images/middle.gif diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala index cabdb6da..083f7077 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo.scala @@ -32,12 +32,12 @@ package scala.swing.examples.tutorials.layout import scala.swing._ -/* +/** * Tutorials: How to Use BoxLayout - * http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemoProject/src/layout/BoxLayoutDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemoProject/src/layout/BoxLayoutDemo.java]] * * BoxLayoutDemo.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala index dd6fa67e..d5e64fd4 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BoxLayoutDemo2.scala @@ -34,13 +34,13 @@ import scala.swing._ import scala.swing.event.ButtonClicked import java.awt.Color -/* +/** * Tutorials: How to Use BoxLayout - * http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html]] * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemo2Project/src/layout/BoxLayoutDemo2.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemo2Project/src/layout/BLDComponent.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemo2Project/src/layout/BoxLayoutDemo2.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemo2Project/src/layout/BLDComponent.java]] * * BoxLayoutDemo2.scala requires BLDComponent.scala. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala index a708f43a..0a4bea9f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala @@ -32,16 +32,16 @@ package scala.swing.examples.tutorials.layout import scala.swing._ -/* +/** * Tutorials: Creating a Custom Layout Manager - * http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java]] * - * CustomLayoutDemo.java requires one other file: - * DiagonalLayout.java + * CustomLayoutDemo.scala requires one other file: + * DiagonalLayout.scala */ class CustomLayoutDemo() extends Panel with SequentialContainer.Wrapper { override lazy val peer: javax.swing.JPanel = diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala index 45bb7451..06e350a3 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/DiagonalLayout.scala @@ -31,7 +31,7 @@ package scala.swing.examples.tutorials.layout /* - * 1.2+ version. Used by CustomLayoutDemo.java. + * 1.2+ version. Used by CustomLayoutDemo.scala. */ import java.awt._ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala index 47708fcf..06f12791 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala @@ -33,16 +33,16 @@ package scala.swing.examples.tutorials.layout import scala.swing._ import javax.swing.UIManager -/* +/** * Tutorials: Creating a Custom Layout Manager - * http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java]] * - * CustomLayoutDemo.java requires one other file: - * DiagonalLayout.java + * CustomLayoutDemo.scala requires one other file: + * DiagonalLayout.scala */ class FlowLayoutDemo() extends FlowPanel { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala index 675c86af..094b8428 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala @@ -37,17 +37,17 @@ import java.awt.Dimension import java.net.URL import javax.swing.{ ImageIcon, JToolBar } -/* +/** * Tutorials: How to Use Actions - * http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html]] * * The graphics in this application require a download of the Java Look and Feel Graphics * Repository from Oracle. - * http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-client-419417.html#7520-jlf-1.0-oth-JPR + * [[http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-client-419417.html#7520-jlf-1.0-oth-JPR]] * Accept the user agreement from the site, unzip, and place the jar file contents in your classpath. * * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/ActionDemoProject/src/misc/ActionDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/ActionDemoProject/src/misc/ActionDemo.java]] * * ActionDemo.scala requires the Java Look and Feel jar file jlfgr-1_0.jar. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala index 61cf1150..2d878e02 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/misc/FocusConceptsDemo.scala @@ -34,12 +34,12 @@ import scala.swing._ import scala.util.control.NonFatal import javax.swing.UIManager -/* +/** * Tutorial: How to Use the Focus System - * http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html + * [[http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html]] * * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/FocusConceptsDemoProject/src/misc/FocusConceptsDemo.java + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/FocusConceptsDemoProject/src/misc/FocusConceptsDemo.java]] * * FocusConceptsDemo.scala requires no other files. * From cbc70f9b0502a19e2dfdd37abda0363bb52bfc3d Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Tue, 30 Sep 2014 21:41:42 -0700 Subject: [PATCH 28/36] FlowLayout, GridLayout, GridBagLayout demos scalified. --- .gitignore | 1 + .../tutorials/layout/FlowLayoutDemo.scala | 57 +++++++++-- .../tutorials/layout/GridBagLayoutDemo.scala | 92 ++++++++++++++++++ .../tutorials/layout/GridLayoutDemo.scala | 97 +++++++++++++++++++ 4 files changed, 239 insertions(+), 8 deletions(-) create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/GridBagLayoutDemo.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala diff --git a/.gitignore b/.gitignore index d3cdbcbb..fa010609 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ build.properties /.settings /examples/.classpath /examples/.project +scala-swing.iml # bak files produced by ./cleanup-commit *.bak diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala index 06f12791..62aecedb 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala @@ -31,21 +31,62 @@ package scala.swing.examples.tutorials.layout import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.ComponentOrientation import javax.swing.UIManager /** - * Tutorials: Creating a Custom Layout Manager - * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html]] + * Tutorials: How to Use FlowLayout + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/flow.html]] * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/FlowLayoutDemoProject/src/layout/FlowLayoutDemo.java]] * - * CustomLayoutDemo.scala requires one other file: - * DiagonalLayout.scala + * FlowLayoutDemo.scala requires no other files */ -class FlowLayoutDemo() extends FlowPanel { - +class FlowLayoutDemo extends BorderPanel { + val RtoL = "Right to left" + val LtoR = "Left to right" + val controls: FlowPanel = new FlowPanel() + val applyButton = new Button("Apply component orientation") + val compsToExperiment = new FlowPanel(FlowPanel.Alignment.Trailing)() + val LtoRbutton = new RadioButton(LtoR) { selected = true } + val RtoLbutton = new RadioButton(RtoL) + + //Add buttons to the experiment layout + compsToExperiment.contents += new Button("Button 1") + compsToExperiment.contents += new Button("Button 2") + compsToExperiment.contents += new Button("Button 3") + compsToExperiment.contents += new Button("Long Named Button 4") + compsToExperiment.contents += new Button("5") + + //Left to right component orientation is selected by default + compsToExperiment.peer.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT) + + //Add controls to set up the component orientation in the experiment layout + val group = new ButtonGroup() { + buttons += LtoRbutton + buttons += RtoLbutton + } + controls.contents += LtoRbutton + controls.contents += RtoLbutton + controls.contents += applyButton + + layout(compsToExperiment) = BorderPanel.Position.Center + layout(controls) = BorderPanel.Position.South + + listenTo(applyButton) + reactions += { + case ButtonClicked(`applyButton`) => + if (LtoRbutton.selected) { + compsToExperiment.peer.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT) + } + else { + compsToExperiment.peer.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) + } + compsToExperiment.peer.validate() + compsToExperiment.peer.repaint() + } } object FlowLayoutDemo extends SimpleSwingApplication { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridBagLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridBagLayoutDemo.scala new file mode 100644 index 00000000..473136d4 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridBagLayoutDemo.scala @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ + +/** + * Tutorials: How to Use GridBagLayout + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html]] + * + * Source code reference: + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/GridBagLayoutDemoProject/src/layout/GridBagLayoutDemo.java]] + * + * GridBagLayoutDemo.scala requires no other files. + */ +class GridBagLayoutDemo extends GridBagPanel { + val shouldFill = true + val shouldWeightX = true + val RightToLeft = false + val c: Constraints = new Constraints() + //natural height, maximum width + if (shouldFill) c.fill = GridBagPanel.Fill.Horizontal + if (shouldWeightX) c.weightx = 0.5 + c.gridx = 0 + c.gridy = 0 + layout(new Button("Button 1")) = c + + c.fill = GridBagPanel.Fill.Horizontal + c.weightx = 0.5 + c.gridx = 1 + c.gridy = 0 + layout(new Button("Button 2")) = c + + c.fill = GridBagPanel.Fill.Horizontal + c.weightx = 0.5 + c.gridx = 2 + c.gridy = 0 + layout(new Button("Button 3")) = c + + c.fill = GridBagPanel.Fill.Horizontal + c.ipady = 40 // make this component tall + c.weightx = 0.5 + c.gridwidth = 3 + c.gridx = 0 + c.gridy = 1 + layout(new Button("Long-Named Button 4")) = c + + c.fill = GridBagPanel.Fill.Horizontal + c.ipady = 0 //reset to default + c.weightx = 1.0 //request any extra vertical space + c.anchor = GridBagPanel.Anchor.PageEnd //bottom of space + c.insets = new Insets(10, 0, 0, 0) // top padding + c.gridx = 1 + c.gridwidth = 2 + c.gridy = 22 + layout(new Button("5")) = c +} + +object GridBagLayoutDemo extends SimpleSwingApplication { + lazy val top = new MainFrame() { + title = "GridBagLayoutDemo" + contents = new GridBagLayoutDemo() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala new file mode 100644 index 00000000..766c7735 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.layout + +import scala.swing._ +import scala.swing.event.ButtonClicked +import javax.swing.UIManager +import java.awt.Dimension + +/** + * Tutorials: How to Use GridLayout + * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html]] + * + * Source code reference: + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/GridLayoutDemoProject/src/layout/GridLayoutDemo.java]] + */ +class GridLayoutDemo extends BorderPanel { + private val gapList = Array("0", "10", "15", "20") + private val maxGap = 20 + val horGapComboBox = new ComboBox(gapList) + val verGapComboBox = new ComboBox(gapList) + val applyButton = new Button("Apply gaps") + val compsToExperiment = new GridPanel(0, 2) + val controls = new GridPanel(2, 3) + //Set up components preferred size + val b = new Button("Just fake button") + val buttonSize = b.preferredSize + compsToExperiment.preferredSize = + new Dimension((buttonSize.getWidth() * 2.5).toInt + maxGap, + (buttonSize.getHeight() * 3.5).toInt + maxGap * 2) + + //Add buttons to experiment with Grid Layout + compsToExperiment.contents += new Label("Horizontal gap:") + compsToExperiment.contents += new Label("Vertical gap:") + compsToExperiment.contents += new Label(" ") + compsToExperiment.contents += horGapComboBox + compsToExperiment.contents += verGapComboBox + compsToExperiment.contents += applyButton + layout(compsToExperiment) = BorderPanel.Position.North + layout(controls) = BorderPanel.Position.South + + listenTo(applyButton) + reactions += { + case ButtonClicked(`applyButton`) => + //Get the horizontal gap value + val horGap = horGapComboBox.selection.item + //Get the vertical gap value + val verGap = verGapComboBox.selection.item + //Set up the horizontal gap value + compsToExperiment.hGap = horGap.toInt + //Set up the vertical gap value + compsToExperiment.vGap = verGap.toInt + //Set up the layout of the buttons + compsToExperiment.peer.getLayout().layoutContainer(compsToExperiment.peer) + } +} + +object GridLayoutDemo extends SimpleSwingApplication { + /* Use an appropriate Look and Feel */ + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") + /* Turn off metal's use bold fonts */ + UIManager.put("swing.boldMetal", false) + //Create and set up the window. + lazy val top = new MainFrame { + title = "GridLayoutDemo" + resizable = false + contents = new GridLayoutDemo() + } +} \ No newline at end of file From 8c0754afa78ee33382c627fd73c55689c35bb85d Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Wed, 1 Oct 2014 00:02:39 -0700 Subject: [PATCH 29/36] Events demos Beeper and ListSelectionDemo. Fixed the orientation of the splitpanes used in SplitPaneDemo, SplitPaneDemo2, and SplitPaneDividerDemo. --- .../tutorials/components/SplitPaneDemo.scala | 12 +- .../tutorials/components/SplitPaneDemo2.scala | 9 +- .../components/SplitPaneDividerDemo.scala | 2 +- .../examples/tutorials/events/Beeper.scala | 65 +++++++++ .../tutorials/events/ListSelectionDemo.scala | 134 ++++++++++++++++++ 5 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/events/Beeper.scala create mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index 2b9f19a2..f579d055 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -37,14 +37,7 @@ import java.awt.Font import java.net.URL import javax.swing.ImageIcon -/** - * Tutorial: How to Use Split Panes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemoProject/src/components/SplitPaneDemo.java]] - */ -//SplitPaneDemo itself is not a visible component. +//SplitPaneDemo itself is not a visible component. It is used by SplitPaneDemo2.scala. class SplitPaneDemo extends FlowPanel { val imageNames: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig", "dukeWaveRed", "kathyCosmo", "left", "middle", "right", "stickerface") @@ -61,7 +54,8 @@ class SplitPaneDemo extends FlowPanel { val pictureScrollPane = new ScrollPane(picture) //Create a split pane with the two scroll panes in it. - val splitPane = new SplitPane(Orientation.Horizontal, listScrollPane, pictureScrollPane) { + //Use Orientation.Vertical to get a left/right split pane + val splitPane = new SplitPane(Orientation.Vertical, listScrollPane, pictureScrollPane) { oneTouchExpandable = true dividerLocation = 150 } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala index d6858335..87486b56 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -42,6 +42,10 @@ import javax.swing.ImageIcon * * Source code reference: * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemo2Project/src/components/SplitPaneDemo2.java]] + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDemoProject/src/components/SplitPaneDemo.java]] + * + * SplitPaneDemo2.scala uses + * SplitPaneDemo.scala */ class SplitPaneDemo2 extends MainFrame { title = "SplitPaneDemo2" @@ -63,8 +67,9 @@ class SplitPaneDemo2 extends MainFrame { } //Create a split pane and put "top" (a split pane) - //and JLabel instance in it. - val splitPane = new SplitPane(Orientation.Vertical, top, label) { + //and JLabel instance in it. + //Use Orientation.Horizontal to get a top/bottom split pane. + val splitPane = new SplitPane(Orientation.Horizontal, top, label) { oneTouchExpandable = true dividerLocation = 180 } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index 3e101a1a..6ac4ac6b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -64,7 +64,7 @@ class SplitPaneDividerDemo extends BorderPanel { } sd2.setMinimumSize(new Dimension(30,30)) - val splitPane = new SplitPane(Orientation.Horizontal, sd1, sd2) { + val splitPane = new SplitPane(Orientation.Vertical, sd1, sd2) { resizeWeight = 0.5 oneTouchExpandable = true continuousLayout = true diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/events/Beeper.scala b/examples/src/main/scala/scala/swing/examples/tutorials/events/Beeper.scala new file mode 100644 index 00000000..3d44e0a5 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/events/Beeper.scala @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.events + +import scala.swing._ +import scala.swing.event.ButtonClicked +import java.awt.{Dimension,Toolkit } + +/** + * Tutorial: Introduction to Event Listeners + * [[http://docs.oracle.com/javase/tutorial/uiswing/events/intro.html]] + * + * Source code reference: + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/events/BeeperProject/src/events/Beeper.java]] + * + * Beeper.scala requires no other files. + */ +class Beeper extends BorderPanel { + val button = new Button("Click Me") { + preferredSize = new Dimension(200, 80) + } + layout(button) = BorderPanel.Position.Center + listenTo(button) + reactions += { + case ButtonClicked(`button`) => + Toolkit.getDefaultToolkit().beep() + } + +} + +object Beeper extends SimpleSwingApplication { + //Create and set up the window. + lazy val top = new MainFrame { + title = "Beeper" + contents = new Beeper() + } +} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala new file mode 100644 index 00000000..f93fe1c4 --- /dev/null +++ b/examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package scala.swing.examples.tutorials.events + +import scala.swing._ +import scala.swing.event.{ButtonClicked, SelectionChanged} +import java.awt.Dimension + +/** + * Tutorial: How to Write a List Selection Listener + * [[http://docs.oracle.com/javase/tutorial/uiswing/events/listselectionlistener.html]] + * + * Source code reference: + * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/events/ListSelectionDemoProject/src/events/ListSelectionDemo.java]] + * + * ListSelectionDemo.scala requires no other files. + */ +class ListSelectionDemo extends BorderPanel { + val listData = Array( "one", "two", "three", "four", + "five", "six", "seven" ) + val columnNames = Array( "French", "Spanish", "Italian" ) + val list = new ListView(listData) + val listPane = new ScrollPane(list) + + val modes = Array( "SINGLE_SELECTION", "SINGLE_INTERVAL_SELECTION", + "MULTIPLE_INTERVAL_SELECTION") + val comboBox = new ComboBox(modes) { + selection.index = 2 + } + val controlPane = new FlowPanel() { + contents += new Label("Selection mode:") + contents += comboBox + } + + //Build output area. + val output = new TextArea(1, 10) { + editable = false + } + val outputPane = new ScrollPane(output) { + verticalScrollBarPolicy = ScrollPane.BarPolicy.Always + horizontalScrollBarPolicy = ScrollPane.BarPolicy.AsNeeded + } + val listContainer = new GridPanel(1, 1) { + contents += listPane + border = Swing.TitledBorder(Swing.EmptyBorder, "List") + } + val topHalf = new BoxPanel(Orientation.Horizontal) { + contents += listContainer + border = Swing.EmptyBorder(5, 5, 0, 5) + minimumSize = new Dimension(100, 50) + preferredSize = new Dimension(100, 110) + } + + val bottomHalf = new BorderPanel() { + layout(controlPane) = BorderPanel.Position.North + layout(outputPane) = BorderPanel.Position.Center + preferredSize = new Dimension(450, 135) + } + + //Do the layout. + val splitPane = new SplitPane(Orientation.Horizontal, topHalf, bottomHalf) + + layout(splitPane) = BorderPanel.Position.Center + + listenTo(comboBox.selection) + listenTo(list.selection) + + reactions += { + case SelectionChanged(`comboBox`) => + val newMode = comboBox.selection.item + newMode match { + case "SINGLE_SELECTION" => + list.selection.intervalMode = ListView.IntervalMode.Single + case "SINGLE_INTERVAL_SELECTION" => + list.selection.intervalMode = ListView.IntervalMode.SingleInterval + case "MULTIPLE_INTERVAL_SELECTION" => + list.selection.intervalMode = ListView.IntervalMode.MultiInterval + } + output.append("----------" + "Mode: " + newMode + "----------" + "\n") + case SelectionChanged(`list`) => + val firstIndex = list.selection.leadIndex + val lastIndex = list.selection.anchorIndex // anchor = last? + val isAdjusting = list.selection.adjusting + output.append("Event for indexes " + firstIndex + " - " + lastIndex + + "; isAdjusting is " + isAdjusting + "; selected indexes:") + if (list.selection.indices.isEmpty) { + output.append(" ") + } + else { + // Find out which indexes are selected. + for (i <- list.selection.indices) { + output.append(" " + i) + } + } + output.append("\n") + output.caret.position = output.peer.getDocument().getLength() + } +} + +object ListSelection extends SimpleSwingApplication { + //Create and set up the window. + lazy val top = new MainFrame { + title = "ListSelectionDemo" + contents = new ListSelectionDemo() + } +} \ No newline at end of file From 943ef110d537960067cff63a068675e30fc63383 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Wed, 1 Oct 2014 11:49:24 -0700 Subject: [PATCH 30/36] Merged changes from Andy Hicks, mostly having to do with createImageIcon. --- .../tutorials/components/ButtonDemo.scala | 25 +- .../tutorials/components/ButtonHtmlDemo.scala | 2 +- .../tutorials/components/CheckboxDemo.scala | 77 +-- .../components/ColorChooserDemo.scala | 6 +- .../tutorials/components/ComboBoxDemo.scala | 29 +- .../tutorials/components/ComboBoxDemo2.scala | 34 +- .../components/CustomComboBoxDemo.scala | 50 +- .../tutorials/components/DialogDemo.scala | 485 +++++++----------- .../components/DocumentSizeFilter.scala | 8 +- .../components/FileChooserDemo.scala | 91 ++-- .../tutorials/components/HtmlDemo.scala | 5 +- .../tutorials/components/IconDemoApp.scala | 134 ++--- .../tutorials/components/MissingIcon.scala | 9 +- 13 files changed, 403 insertions(+), 552 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala index 5f0f8ca8..e12900f8 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonDemo.scala @@ -47,28 +47,28 @@ import javax.swing.UIManager * /scala/swing/examples/tutorials/images/left.gif */ class ButtonDemo extends FlowPanel { - val leftButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get - val middleButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val rightButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get - // + val leftButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/right.gif") + val middleButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") + val rightButtonIcon = ButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/left.gif") + val disable: Button = new Button("Disable middle button") { - icon = leftButtonIcon + leftButtonIcon.foreach( icon = _) verticalTextPosition = Alignment.Center horizontalTextPosition = Alignment.Leading mnemonic = event.Key.D tooltip = "Click this button to disable the middle button." } - // + val middle: Button = new Button("Middle button") { - icon = middleButtonIcon + middleButtonIcon.foreach( icon = _ ) verticalTextPosition = Alignment.Bottom horizontalTextPosition = Alignment.Center mnemonic = event.Key.M tooltip = "This middle button does nothing when you click it." } - // + val enable: Button = new Button("Enable middle button") { - icon = rightButtonIcon + rightButtonIcon.foreach( icon = _ ) enabled = false mnemonic = event.Key.E tooltip = "Click this button to enable the middle button." @@ -82,8 +82,8 @@ class ButtonDemo extends FlowPanel { listenTo(enable) reactions += { - case ButtonClicked(`enable`) => enableMiddle - case ButtonClicked(`disable`) => disableMiddle + case ButtonClicked(`enable`) => enableMiddle() + case ButtonClicked(`disable`) => disableMiddle() } def enableMiddle(): Unit = { @@ -91,7 +91,8 @@ class ButtonDemo extends FlowPanel { middle.enabled = true disable.enabled = true } - def disableMiddle(): Unit = { + + def disableMiddle(): Unit = { enable.enabled = true middle.enabled = false disable.enabled = false diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala index 1e3a4444..06fda6ec 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -111,6 +111,6 @@ object ButtonHtmlDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "ButtonHtmlDemo" //Create and set up the content pane. - contents = new ButtonHtmlDemo(); + contents = new ButtonHtmlDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index 4a56a178..8b3a4f12 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -34,8 +34,8 @@ import scala.swing._ import scala.swing.event.ButtonClicked import scala.swing.event.Key import java.awt.Font -import javax.swing.ImageIcon -import java.net.URL + +import scala.swing.examples.tutorials.components.ButtonDemo._ /** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons @@ -83,21 +83,25 @@ class CheckboxDemo extends BorderPanel { */ //Create the check boxes. - val chinButton = new CheckBox("Chin") - chinButton.mnemonic = Key.C // .VK_C - chinButton.selected = true + val chinButton = new CheckBox("Chin") { + mnemonic = Key.C // .VK_C + selected = true + } - val glassesButton = new CheckBox("Glasses") - glassesButton.mnemonic = Key.G; - glassesButton.selected = true + val glassesButton = new CheckBox("Glasses") { + mnemonic = Key.G + selected = true + } - val hairButton = new CheckBox("Hair") - hairButton.mnemonic = Key.H - hairButton.selected = true + val hairButton = new CheckBox("Hair") { + mnemonic = Key.H + selected = true + } - val teethButton = new CheckBox("Teeth") - teethButton.mnemonic = Key.T - teethButton.selected = true + val teethButton = new CheckBox("Teeth") { + mnemonic = Key.T + selected = true + } //Indicates what's on the geek. val choices: StringBuffer = new StringBuffer("cght") @@ -125,34 +129,31 @@ class CheckboxDemo extends BorderPanel { listenTo(hairButton) listenTo(teethButton) + + def changeState( idx:Int, checkBox: CheckBox, label:Char ): Unit = { + choices.setCharAt(idx, if (checkBox.selected) label else '-' ) + updatePicture() + } + reactions += { - case ButtonClicked(`chinButton`) => - choices.setCharAt(0, if (!chinButton.selected) '-' else 'c') - updatePicture() - case ButtonClicked(`glassesButton`) => - choices.setCharAt(1, if (!glassesButton.selected) '-' else 'g') - updatePicture() - case ButtonClicked(`hairButton`) => - choices.setCharAt(2, if (!hairButton.selected) '-' else 'h') - updatePicture() - case ButtonClicked(`teethButton`) => - choices.setCharAt(3, if (!teethButton.selected) '-' else 't') - updatePicture() + case ButtonClicked(`chinButton`) => changeState(0, chinButton, 'c') + case ButtonClicked(`glassesButton`) => changeState(1, glassesButton, 'g') + case ButtonClicked(`hairButton`) => changeState(2, hairButton, 'h') + case ButtonClicked(`teethButton`) => changeState(3, teethButton, 't') } def updatePicture(): Unit = { + pictureLabel.tooltip = choices.toString + //Get the icon corresponding to the image. - val s = choices.toString() - val icon: Option[ImageIcon] = CheckboxDemo.createImageIcon( - "/scala/swing/examples/tutorials/images/geek/geek-" - + choices.toString() - + ".gif") - pictureLabel.icon = if (icon.isDefined) icon.get else Swing.EmptyIcon - pictureLabel.tooltip = choices.toString() - if (icon == null) { - pictureLabel.text = "Missing Image" - } else { - pictureLabel.text = null + createImageIcon( s"/scala/swing/examples/tutorials/images/geek/geek-$choices.gif") match { + case Some( icon ) => + pictureLabel.icon = icon + pictureLabel.text = null + case None => + pictureLabel.icon = Swing.EmptyIcon + pictureLabel.text = "Missing Image" + } } } @@ -165,6 +166,6 @@ object CheckboxDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "CheckboxDemo" //Create and set up the content pane. - contents = new CheckboxDemo(); + contents = new CheckboxDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala index fbf74bec..ca1b9091 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ColorChooserDemo.scala @@ -41,12 +41,10 @@ import java.awt.{ Color, Dimension, Font } * * Source code reference: * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ColorChooserDemoProject/src/components/ColorChooserDemo.java]] - * - * ColorChooserDemo.scala requires no other files. */ class ColorChooserDemo extends BorderPanel { //Set up the banner at the top of the window - val banner = new Label("Welcome to the Tutorial Zone!", EmptyIcon, Alignment.Center) { + val banner = new Label("Welcome to the Scala-Swing Zone!", EmptyIcon, Alignment.Center) { foreground = Color.yellow background = Color.blue opaque = true @@ -75,6 +73,6 @@ object ColorChooserDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "ColorChooserDemo" //Create and set up the content pane. - contents = new ColorChooserDemo(); + contents = new ColorChooserDemo() } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index ac4b0744..840f1350 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -32,10 +32,10 @@ package scala.swing.examples.tutorials.components import scala.swing._ -import scala.swing.event.{ SelectionChanged } +import scala.swing.event.SelectionChanged import java.awt.{ Dimension, Font } -import javax.swing.{ BorderFactory, ImageIcon } -import java.net.URL +import javax.swing.BorderFactory + /** * Tutorial: How to Use Combo Boxes @@ -55,10 +55,10 @@ class ComboBoxDemo extends BorderPanel { } //Set up the picture label. - val imgIcon = ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" - + petList.selection.item + ".gif") + val imgIcon = ComboBoxDemo.createImageIcon(s"/scala/swing/examples/tutorials/images/${petList.selection.item}.gif") + val picture = new Label() { - icon = if (imgIcon.isDefined) imgIcon.get else Swing.EmptyIcon + icon = imgIcon.getOrElse( Swing.EmptyIcon ) font = font.deriveFont(Font.ITALIC) horizontalAlignment = Alignment.Center //The preferred size is hard-coded to be the width of the @@ -78,25 +78,20 @@ class ComboBoxDemo extends BorderPanel { } def updateLabel(s: String): Unit = { - val ic = ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + s + ".gif") - picture.icon = if (ic.isDefined) imgIcon.get else Swing.EmptyIcon + picture.icon = + ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + s + ".gif").getOrElse( Swing.EmptyIcon ) } } object ComboBoxDemo extends SimpleSwingApplication { - val birdString = "Bird" - val catString = "Cat" - val dogString = "Dog" - val rabbitString = "Rabbit" - val pigString = "Pig" - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + /** Returns an ImageIcon option, or None if the path was invalid. */ + def createImageIcon(path: String ): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } + lazy val top = new MainFrame() { title = "ComboBoxDemo" //Create and set up the content pane. - contents = new ComboBoxDemo(); + contents = new ComboBoxDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala index 6fd3f393..eb65b45b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -37,14 +37,15 @@ import java.awt.Color import java.util.Date import java.text.SimpleDateFormat + +import scala.util.{Try, Failure, Success} + /** * Tutorial: How to Use Combo Boxes * [[http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html]] * * Source code reference: * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemo2Project/src/components/ComboBoxDemo2.java]] - * - * ComboBoxDemo2.scala requires no other files. */ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { val patternExamples = Array[String]( @@ -85,14 +86,14 @@ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { val patternPanel = new BoxPanel(Orientation.Vertical) { contents += patternLabel1 contents += patternLabel2 - xLayoutAlignment = 0.0 // Left + xLayoutAlignment = java.awt.Component.LEFT_ALIGNMENT contents += patternList } val resultPanel = new GridPanel(0,1) { contents += resultLabel contents += result - xLayoutAlignment = 0.0 // Left + xLayoutAlignment = java.awt.Component.LEFT_ALIGNMENT } contents += patternPanel @@ -102,21 +103,20 @@ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { listenTo(patternList.selection) reactions += { - case SelectionChanged(`patternList`) => // currentPattern = patternList.selection.item - reformat() + case SelectionChanged(`patternList`) => reformat() } def reformat(): Unit = { - val today = new Date() - val formatter = new SimpleDateFormat(patternList.selection.item) - try { - val dateString = formatter.format(today) - result.foreground = Color.black - result.text = dateString - } - catch { - case iae: IllegalArgumentException => result.foreground = Color.red - result.text = "Error: " + iae.getMessage() + Try { + val today = new Date() + val formatter = new SimpleDateFormat(patternList.selection.item) + formatter.format(today) + } match { + case Success( dateString) => + result.foreground = Color.black + result.text = dateString + case Failure( err ) => + result.text = s"Error: ${err.getMessage}" } } } @@ -125,6 +125,6 @@ object ComboBoxDemo2 extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "ComboBoxDemo2" //Create and set up the content pane. - contents = new ComboBoxDemo2(); + contents = new ComboBoxDemo2() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index 48b685cb..27687ce9 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -33,7 +33,6 @@ package scala.swing.examples.tutorials.components import scala.swing._ import javax.swing.ImageIcon -import java.net.URL import java.awt.{ Dimension, Font } /** @@ -52,8 +51,8 @@ import java.awt.{ Dimension, Font } */ class CustomComboBoxDemo extends BorderPanel { val petStrings: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig") - val images: Array[Option[ImageIcon]] = new Array[Option[ImageIcon]](petStrings.length) - val intArray: Array[Int] = new Array[Int](petStrings.length) +// val images: Array[Option[ImageIcon]] = new Array[Option[ImageIcon]](petStrings.length) + val intArray: Array[Int] = (0 until petStrings.length ).toArray /* * Despite its use of EmptyBorder, this panel makes a fine content * pane because the empty border just increases the panel's size @@ -62,14 +61,11 @@ class CustomComboBoxDemo extends BorderPanel { * opaque (which it is by default); adding a border doesn't change * that. */ - for (i <- 0 until petStrings.length) { - val oImage = CustomComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + petStrings(i) + ".gif") - if (oImage.isDefined) { - oImage.get.setDescription(petStrings(i)) - } - images(i) = oImage - intArray(i) = i - } + + val images:Array[Option[ImageIcon]] = petStrings.map( pet => { + val oImage = CustomComboBoxDemo.createImageIcon(s"/scala/swing/examples/tutorials/images/$pet.gif") + oImage.map( img => {img.setDescription(pet); img} ) + }) //Create the combo box. val petList = new ComboBox[Int](intArray) { @@ -79,7 +75,7 @@ class CustomComboBoxDemo extends BorderPanel { } //Lay out the demo. - layout(petList) = BorderPanel.Position.North + layout(petList) = BorderPanel.Position.Center border = Swing.EmptyBorder(20, 20, 20, 20) class ComboBoxRenderer extends ListView.AbstractRenderer[Int, Label](new Label("")) { @@ -89,30 +85,23 @@ class CustomComboBoxDemo extends BorderPanel { * to the selected value and returns the label, set up * to display the text and image. */ - def configure( - listMe: ListView[_], - isSelected: Boolean, - cellHasFocus: Boolean, - a: Int, - index: Int) = { + def configure( listMe: ListView[_], isSelected: Boolean, cellHasFocus: Boolean, a: Int, index: Int): Unit = { //Set the icon and text. If icon was null, say so. - component.icon = images(a).get - val pet = petStrings(a) - if (component.icon != null) { - component.text = pet; - component.font = listMe.font - } else { - setUhOhText(pet + " (no image available)", - listMe.font) + images(a) match { + case Some( icon ) => + component.icon = icon + component.text = petStrings(a) + component.font = listMe.font + case None => setUhOhText( s"${petStrings(a)} (no image available)", listMe.font) } } //Set the font and text when no image was found. - def setUhOhText(uhOhText: String, normalFont: Font) = { + def setUhOhText(uhOhText: String, normalFont: Font): Unit = { if (!uhOhFont.isDefined) { //lazily create this font uhOhFont = Some(normalFont.deriveFont(Font.ITALIC)) } - component.font = uhOhFont.get + component.font = uhOhFont.getOrElse( normalFont ) component.text = uhOhText } } @@ -127,8 +116,11 @@ object CustomComboBoxDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "CustomComboBoxDemo" + //Create and set up the content pane. - contents = new CustomComboBoxDemo(); + val newContentPane = new CustomComboBoxDemo() + newContentPane.opaque = true + contents = newContentPane } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index 0e31ba60..2d45907f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -34,7 +34,6 @@ import scala.swing._ import scala.swing.event.ButtonClicked import scala.swing.TabbedPane.Page import javax.swing.border.Border -import java.net.URL import javax.swing.ImageIcon import java.awt.{ Dimension, Font } @@ -85,128 +84,75 @@ class DialogDemo(val frame: Frame) extends BorderPanel { } /** Creates the panel shown by the first tab. */ private def createSimpleDialogBox(): BorderPanel = { - val numButtons = 4 - val radioButtons: Array[RadioButton] = new Array[RadioButton](numButtons) val showItButton: Button = new Button("Show it!") - val defaultMessageCommand = "default" - val yesNoCommand = "yesno" - val yeahNahCommand = "yeahnah" - val yncCommand = "ync" + val defaultMessageCommandButton =new RadioButton("OK (in the L&F's words)") { selected = true } + val yesNoCommandButton = new RadioButton("Yes/No (in the L&F's words)") + val yeahNahCommandButton = new RadioButton("Yes/No (in the programmer's words)") + val yncCommandButton = new RadioButton("Yes/No/Cancel (in the programmer's words)") - val group: ButtonGroup = new ButtonGroup() { - - } + val radioButtons:Array[RadioButton] = Array( + defaultMessageCommandButton, + yesNoCommandButton, + yeahNahCommandButton, + yncCommandButton + ) - radioButtons(0) = new RadioButton("OK (in the L&F's words)") { - selected = true + val group: ButtonGroup = new ButtonGroup() { + radioButtons.foreach( buttons += _ ) } - // radioButtons[0].setActionCommand(defaultMessageCommand) - - radioButtons(1) = new RadioButton("Yes/No (in the L&F's words)") - // radioButtons[1].setActionCommand(yesNoCommand) - - radioButtons(2) = new RadioButton("Yes/No " - + "(in the programmer's words)") - // radioButtons[2].setActionCommand(yeahNahCommand) - - radioButtons(3) = new RadioButton("Yes/No/Cancel " - + "(in the programmer's words)") - // radioButtons[3].setActionCommand(yncCommand) + listenTo(showItButton) - val defaultMessageCommandButton = radioButtons(0) - val yesNoCommandButton = radioButtons(1) - val yeahNahCommandButton = radioButtons(2) - val yncCommandButton = radioButtons(3) + reactions += { - for (i <- 0 until numButtons) { - group.buttons += radioButtons(i) - } + case ButtonClicked(`showItButton`) if group.selected == Some(defaultMessageCommandButton) => + Dialog.showMessage(this, "Eggs aren't supposed to be green.") + + case ButtonClicked(`showItButton`) if group.selected == Some(yesNoCommandButton) => + Dialog.showConfirmation( + this, "Would you like green eggs and ham?", + "An Inane Question", + Dialog.Options.YesNo) match { + case Dialog.Result.Yes => setLabel("Ewww!") + case Dialog.Result.No => setLabel("Me neither!") + case _ => setLabel("Come on -- tell me!") + } + + + + case ButtonClicked(`showItButton`) if group.selected == Some(yeahNahCommandButton) => + Dialog.showOptions(this, + "Would you like green eggs and ham?", + "A Silly Question", + Dialog.Options.YesNo, + Dialog.Message.Question, + Swing.EmptyIcon, + Array("Yes, please", "No way!"), + 0) match { + + case Dialog.Result.Yes => setLabel("You're kidding!") + case Dialog.Result.No => setLabel("I don't like them, either.") + case _ => setLabel("Come on -- 'fess up!") + } - var actionCommand = defaultMessageCommand - listenTo(showItButton) - listenTo(defaultMessageCommandButton) - listenTo(yesNoCommandButton) - listenTo(yeahNahCommandButton) - listenTo(yncCommandButton) - reactions += { - case ButtonClicked(`defaultMessageCommandButton`) => - actionCommand = defaultMessageCommand - case ButtonClicked(`yesNoCommandButton`) => - actionCommand = yesNoCommand - case ButtonClicked(`yeahNahCommandButton`) => - actionCommand = yeahNahCommand - case ButtonClicked(`yncCommandButton`) => - actionCommand = yncCommand - case ButtonClicked(`showItButton`) => - actionCommand match { - //ok dialog - case "default" => - val command: String = defaultMessageCommand - Dialog.showMessage(this, - "Eggs aren't supposed to be green.") - //yes/no dialog - case "yesno" => - val n = Dialog.showConfirmation( - this, "Would you like green eggs and ham?", - "An Inane Question", - Dialog.Options.YesNo) - - if (n == Dialog.Result.Yes) { - setLabel("Ewww!"); - } else if (n == Dialog.Result.No) { - setLabel("Me neither!"); - } else { - setLabel("Come on -- tell me!"); - } - //yes/no (not in those words) - case "yeahnah" => - val options: Array[String] = Array("Yes, please", "No way!") - val n = Dialog.showOptions(this, - "Would you like green eggs and ham?", - "A Silly Question", - Dialog.Options.YesNo, - Dialog.Message.Question, - Swing.EmptyIcon, - options, - 0) - if (n == Dialog.Result.Yes) { - setLabel("You're kidding!") - } else if (n == Dialog.Result.No) { - setLabel("I don't like them, either.") - } else { - setLabel("Come on -- 'fess up!") - } - //yes/no/cancel (not in those words) - case "ync" => - val options: Array[String] = Array("Yes, please", - "No, thanks", - "No eggs, no ham!") - val n = Dialog.showOptions(this, - "Would you like some green eggs to go " - + "with that ham?", - "A Silly Question", - Dialog.Options.YesNoCancel, - Dialog.Message.Question, - null, - options, - 2) - if (n == Dialog.Result.Yes) { - setLabel("Here you go: green eggs and ham!") - } else if (n == Dialog.Result.No) { - setLabel("OK, just the ham, then.") - } else if (n == Dialog.Result.Cancel) { - setLabel("Well, I'm certainly not going to eat them!") - } else { - setLabel("Please tell me what you want!") - } + case ButtonClicked(`showItButton`) if group.selected == Some(yncCommandButton) => + Dialog.showOptions(this, + "Would you like some green eggs to go with that ham?", + "A Silly Question", + Dialog.Options.YesNoCancel, + Dialog.Message.Question, + null, + Array("Yes, please", "No, thanks", "No eggs, no ham!"), + 2) match { + case Dialog.Result.Yes => setLabel("Here you go: green eggs and ham!") + case Dialog.Result.No => setLabel("OK, just the ham, then.") + case Dialog.Result.Cancel => setLabel("Well, I'm certainly not going to eat them!") + case _ => setLabel("Please tell me what you want!") } } - createPane(simpleDialogDesc + ":", - radioButtons, - showItButton) + createPane(simpleDialogDesc + ":", radioButtons, showItButton) } /** @@ -214,25 +160,17 @@ class DialogDemo(val frame: Frame) extends BorderPanel { * to create a pane containing a description, a single column * of radio buttons, and the Show it! button. */ - private def createPane(description: String, - radioButtons: Array[RadioButton], - showButton: Button): BorderPanel = { + private def createPane(description: String, radioButtons: Array[RadioButton], showButton: Button): BorderPanel = { - val numChoices = radioButtons.length - val label = new Label(description) val box: BoxPanel = new BoxPanel(Orientation.Vertical) { - contents += label + contents += new Label(description) + radioButtons.foreach( contents += _ ) } - for (i <- 0 until numChoices) { - box.contents += radioButtons(i); - } - - val pane = new BorderPanel() { + new BorderPanel() { layout(box) = BorderPanel.Position.North layout(showButton) = BorderPanel.Position.South } - pane } /** @@ -253,11 +191,11 @@ class DialogDemo(val frame: Frame) extends BorderPanel { grid.xLayoutAlignment = 0.0f contents += grid } - val pane = new BorderPanel() { + + new BorderPanel() { layout(box) = BorderPanel.Position.North layout(showButton) = BorderPanel.Position.South } - pane } /* * Creates the panel shown by the 3rd tab. @@ -266,225 +204,184 @@ class DialogDemo(val frame: Frame) extends BorderPanel { * kind of dialog, as well. */ def createIconDialogBox(): BorderPanel = { - val numButtons = 6 - val radioButtons: Array[RadioButton] = new Array[RadioButton](numButtons) - val plainCommand = "plain" - val infoCommand = "info" - val questionCommand = "question" - val errorCommand = "error" - val warningCommand = "warning" - val customCommand = "custom" - radioButtons(0) = new RadioButton("Plain (no icon)") { - selected = true - } - val plainCommandButton = radioButtons(0) - radioButtons(1) = new RadioButton("Information icon") - val infoCommandButton = radioButtons(1) - radioButtons(2) = new RadioButton("Question icon") - val questionCommandButton = radioButtons(2) - radioButtons(3) = new RadioButton("Error icon") - val errorCommandButton = radioButtons(3) - radioButtons(4) = new RadioButton("Warning icon") - val warningCommandButton = radioButtons(4) - radioButtons(5) = new RadioButton("Custom icon") - val customCommandButton = radioButtons(5) + val plainCommandButton = new RadioButton("Plain (no icon)") { selected = true } + val infoCommandButton = new RadioButton("Information icon") + val questionCommandButton = new RadioButton("Question icon") + val errorCommandButton = new RadioButton("Error icon") + val warningCommandButton = new RadioButton("Warning icon") + val customCommandButton = new RadioButton("Custom icon") + + val radioButtons = Array( + plainCommandButton, + infoCommandButton, + questionCommandButton, + errorCommandButton, + warningCommandButton, + customCommandButton + ) val group: ButtonGroup = new ButtonGroup() { - for (i <- 0 until numButtons) { - buttons += radioButtons(i) - } + radioButtons.foreach( buttons += _ ) } val showItButton = new Button("Show it!") - var actionCommand = plainCommand - listenTo(plainCommandButton) - listenTo(infoCommandButton) - listenTo(questionCommandButton) - listenTo(errorCommandButton) - listenTo(warningCommandButton) - listenTo(customCommandButton) + listenTo(showItButton) + reactions += { - case ButtonClicked(`plainCommandButton`) => actionCommand = plainCommand - case ButtonClicked(`infoCommandButton`) => actionCommand = infoCommand - case ButtonClicked(`questionCommandButton`) => actionCommand = questionCommand - case ButtonClicked(`errorCommandButton`) => actionCommand = errorCommand - case ButtonClicked(`warningCommandButton`) => actionCommand = warningCommand - case ButtonClicked(`customCommandButton`) => actionCommand = customCommand - case ButtonClicked(`showItButton`) => - actionCommand match { - //no icon - case "plain" => + case ButtonClicked(`showItButton`) if group.selected == Some(plainCommandButton) => Dialog.showMessage(this, "Eggs aren't supposed to be green.", "A plain message", Dialog.Message.Plain) - //information icon - case "info" => + + case ButtonClicked(`showItButton`) if group.selected == Some(infoCommandButton) => Dialog.showMessage(this, "Eggs aren't supposed to be green.", "Inane informational dialog", Dialog.Message.Info) - //question icon - case "question" => + + case ButtonClicked(`showItButton`) if group.selected == Some(questionCommandButton) => Dialog.showMessage(this, "You shouldn't use a message dialog " + "(like this)\n" + "for a question, OK?", "Inane question", Dialog.Message.Question) - //error icon - case "error" => + + case ButtonClicked(`showItButton`) if group.selected == Some(errorCommandButton) => Dialog.showMessage(this, "Eggs aren't supposed to be green.", "Inane error", Dialog.Message.Error) - //warning icon - case "warning" => + + case ButtonClicked(`showItButton`) if group.selected == Some(warningCommandButton) => Dialog.showMessage(this, "Eggs aren't supposed to be green.", "Inane warning", Dialog.Message.Warning) - //custom icon - case "custom" => + + case ButtonClicked(`showItButton`) if group.selected == Some(customCommandButton) => Dialog.showMessage(this, "Eggs aren't supposed to be green.", "Inane custom dialog", Dialog.Message.Info, icon) - } - } + } + create2ColPane(iconDesc + ":", radioButtons, showItButton) } /** Creates the panel shown by the second tab. */ private def createFeatureDialogBox(): BorderPanel = { - val numButtons = 5 - val radioButtons: Array[RadioButton] = new Array[RadioButton](numButtons) - val pickOneCommand = "pickone" - val textEnteredCommand = "textfield" - val nonAutoCommand = "nonautooption" - val customOptionCommand = "customoption" - val nonModalCommand = "nonmodal" - radioButtons(0) = new RadioButton("Pick one of several choices") { - selected = true - } - val pickOneCommandButton = radioButtons(0) - radioButtons(1) = new RadioButton("Enter some text") - val textEnteredCommandButton = radioButtons(1) - radioButtons(2) = new RadioButton("Non-auto-closing dialog") - val nonAutoCommandButton = radioButtons(2) - radioButtons(3) = new RadioButton("Input-validating dialog " + - "(with custom message area)") - val customOptionCommandButton = radioButtons(3) - radioButtons(4) = new RadioButton("Non-modal dialog") - val nonModalCommandButton = radioButtons(4) +// val pickOneCommand = "pickone" +// val textEnteredCommand = "textfield" +// val nonAutoCommand = "nonautooption" +// val customOptionCommand = "customoption" +// val nonModalCommand = "nonmodal" + + val pickOneCommandButton = new RadioButton("Pick one of several choices") { selected = true } + + val textEnteredCommandButton = new RadioButton("Enter some text") + val nonAutoCommandButton = new RadioButton("Non-auto-closing dialog") + val customOptionCommandButton = new RadioButton("Input-validating dialog (with custom message area)") + val nonModalCommandButton = new RadioButton("Non-modal dialog") + + val radioButtons = Array( + pickOneCommandButton, + textEnteredCommandButton, + nonAutoCommandButton, + customOptionCommandButton, + nonModalCommandButton + ) val group: ButtonGroup = new ButtonGroup() { - for (i <- 0 until numButtons) { - buttons += radioButtons(i) - } + radioButtons.foreach( buttons += _ ) } + val showItButton = new Button("Show it!") - var actionCommand = pickOneCommand - listenTo(pickOneCommandButton) - listenTo(textEnteredCommandButton) - listenTo(nonAutoCommandButton) - listenTo(customOptionCommandButton) - listenTo(nonModalCommandButton) + listenTo(showItButton) + reactions += { - case ButtonClicked(`pickOneCommandButton`) => actionCommand = pickOneCommand - case ButtonClicked(`textEnteredCommandButton`) => actionCommand = textEnteredCommand - case ButtonClicked(`nonAutoCommandButton`) => actionCommand = nonAutoCommand - case ButtonClicked(`customOptionCommandButton`) => actionCommand = customOptionCommand - case ButtonClicked(`nonModalCommandButton`) => actionCommand = nonModalCommand - case ButtonClicked(`showItButton`) => - actionCommand match { - //pick one of many - case "pickone" => - val possibilities = Array("ham", "spam", "yam") - val s: Option[String] = Dialog.showInput[String](this, - "Complete the sentence:\n" + - "\"Green eggs and...\"", - "Customized Dialog", - Dialog.Message.Plain, - icon, - possibilities, - "ham") - if (s.isDefined && s.get.length > 0) { - setLabel("Green eggs and..." + s.get + "!") - } else { - setLabel("Come on, finish the sentence!") - } - //text input - case "textfield" => - val s: Option[String] = Dialog.showInput[String](this, - "Complete the sentence:\n" + - "\"Green eggs and...\"", - "Customized Dialog", - Dialog.Message.Plain, - icon, - Nil, - "ham") - if (s.isDefined && s.get.length > 0) { - setLabel("Green eggs and..." + s.get + "!") - } else { - setLabel("Come on, finish the sentence!") - } - //non-auto-closing dialog - case "nonautooption" => - setLabel("Not supported.") - //non-auto-closing dialog with custom message area - //NOTE: if you don't intend to check the input, - //then just use showInputDialog instead. - case "customoption" => - setLabel("Not supported.") - //non-modal dialog - case "nonmodal" => - val dialog = new Dialog(frame, frame.peer.getGraphicsConfiguration()) { - title = "A Non-Modal Dialog" - - val label: Label = new Label("

" + - "This is a non-modal dialog.
" + - "You can have one or more of these up
" + - "and still use the main window.") { - horizontalAlignment = Alignment.Center - val myFont = font - font = myFont.deriveFont(Font.PLAIN, 14.0f) - } - val closeButton: Button = new Button("Close") - - val closePanel = new BoxPanel(Orientation.Horizontal) { - contents += Swing.HGlue - contents += closeButton - border = Swing.EmptyBorder(0, 0, 5, 5) - } - - val contentPane: BorderPanel = new BorderPanel() { - layout(label) = BorderPanel.Position.Center - layout(closePanel) = BorderPanel.Position.South - opaque = true - } - contents = contentPane - listenTo(closeButton) - reactions += { - case ButtonClicked(`closeButton`) => - visible = false - dispose() - } - } - dialog.size = new Dimension(300, 150) - dialog.peer.setLocationRelativeTo(frame.peer) - dialog.visible = true + case ButtonClicked(`showItButton`) if group.selected == Some(pickOneCommandButton) => + Dialog.showInput[String](this, + "Complete the sentence:\n" + + "\"Green eggs and...\"", + "Customized Dialog", + Dialog.Message.Plain, + icon, + Array("ham", "spam", "yam"), + "ham") match { + case Some(msg) if msg.length > 1 => setLabel(s"Green eggs and...$msg!") + case _ => setLabel("Come on, finish the sentence!") } - } + + case ButtonClicked(`showItButton`) if group.selected == Some(textEnteredCommandButton) => + Dialog.showInput[String](this, + "Complete the sentence:\n" + + "\"Green eggs and...\"", + "Customized Dialog", + Dialog.Message.Plain, + icon, + Nil, + "ham") match { + case Some(msg) if msg.length > 1 => setLabel(s"Green eggs and...$msg!") + case _ => setLabel("Come on, finish the sentence!") + } + + case ButtonClicked(`showItButton`) if group.selected == Some(nonAutoCommandButton) => + setLabel("Not supported.") + //non-auto-closing dialog with custom message area + //NOTE: if you don't intend to check the input, + //then just use showInputDialog instead. + + case ButtonClicked(`showItButton`) if group.selected == Some(customOptionCommandButton) => + setLabel("Not supported.") + + case ButtonClicked(`showItButton`) if group.selected == Some(nonModalCommandButton) => + val dialog = new Dialog(frame, frame.peer.getGraphicsConfiguration) { + title = "A Non-Modal Dialog" + + val label: Label = new Label("

" + + "This is a non-modal dialog.
" + + "You can have one or more of these up
" + + "and still use the main window.") { + horizontalAlignment = Alignment.Center + font = font.deriveFont(Font.PLAIN, 14.0f) + } + val closeButton: Button = new Button("Close") + + val closePanel = new BoxPanel(Orientation.Horizontal) { + contents += Swing.HGlue + contents += closeButton + border = Swing.EmptyBorder(0, 0, 5, 5) + } + + val contentPane: BorderPanel = new BorderPanel() { + layout(label) = BorderPanel.Position.Center + layout(closePanel) = BorderPanel.Position.South + opaque = true + } + contents = contentPane + listenTo(closeButton) + reactions += { + case ButtonClicked(`closeButton`) => + visible = false + dispose() + } + } + dialog.size = new Dimension(300, 150) + dialog.peer.setLocationRelativeTo(frame.peer) + dialog.visible = true + } createPane(moreDialogDesc + ":", radioButtons, showItButton) } } object DialogDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or None if the path was invalid. */ + + /** Returns an ImageIcon option, or None if the path was invalid. */ def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } @@ -492,6 +389,6 @@ object DialogDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "DialogDemo" //Create and set up the content pane. - contents = new DialogDemo(this); + contents = new DialogDemo(this) } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala index 157d6e6e..54d5a54e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DocumentSizeFilter.scala @@ -44,10 +44,10 @@ class DocumentSizeFilter(val maxCharacters: Int) extends DocumentFilter { //the contents too long. Another option would be //to truncate the inserted string so the contents //would be exactly maxCharacters in length. - if ((fb.getDocument().getLength() + str.length) <= maxCharacters) { + if ((fb.getDocument.getLength + str.length) <= maxCharacters) { super.insertString(fb, offs, str, a) } else { - Toolkit.getDefaultToolkit().beep() + Toolkit.getDefaultToolkit.beep() } } @@ -59,10 +59,10 @@ class DocumentSizeFilter(val maxCharacters: Int) extends DocumentFilter { //the contents too long. Another option would be //to truncate the replacement string so the contents //would be exactly maxCharacters in length. - if ((fb.getDocument().getLength() + str.length - length) <= maxCharacters) { + if ((fb.getDocument.getLength + str.length - length) <= maxCharacters) { super.replace(fb, offs, length, str, a) } else { - Toolkit.getDefaultToolkit().beep() + Toolkit.getDefaultToolkit.beep() } } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala index d8ecc216..13b5141f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala @@ -34,7 +34,6 @@ import scala.swing._ import scala.swing.event._ import java.io.File -import java.net.URL /** * Tutorial: How to Use File Choosers @@ -47,12 +46,12 @@ import java.net.URL * /scala/swing/examples/tutorials/images/Open16.gif * /scala/swing/examples/tutorials/images/Save16.gif */ -object FileChooserDemo extends SimpleSwingApplication { - private val newline = "\n" +class FileChooserDemo extends BorderPanel { - val log = new TextArea(5, 20) - log.peer.setMargin(new Insets(5, 5, 5, 5)) - log.editable = false + val log = new TextArea(5, 20) { + peer.setMargin(new Insets(5, 5, 5, 5)) + editable = false + } val logScrollPane = new ScrollPane(log) //Create a file chooser @@ -71,56 +70,64 @@ object FileChooserDemo extends SimpleSwingApplication { //Create the open button. We use the image from the JLF //Graphics Repository (but we extracted it from the jar). - val openButton = new Button("Open a File...") - val openIconURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/Open16.gif") - if (openIconURL != null) { - openButton.icon = Swing.Icon(openIconURL) + val openButton = new Button("Open a File...") { + FileChooserDemo.createImageIcon("/scala/swing/examples/tutorials/images/Open16.gif").foreach( icn => + icon = icn + ) } - + //Create the save button. We use the image from the JLF //Graphics Repository (but we extracted it from the jar). - val saveButton = new Button("Save a File...") - val saveIconURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/Save16.gif") - if (saveIconURL != null) { - saveButton.icon = Swing.Icon(saveIconURL) + val saveButton = new Button("Save a File...") { + FileChooserDemo.createImageIcon("/scala/swing/examples/tutorials/images/Save16.gif").foreach( icn => + icon = icn + ) } - + //For layout purposes, put the buttons in a separate panel val buttonPanel = new FlowPanel() { contents += openButton contents += saveButton } - lazy val top = new MainFrame { - title = "FileChooserDemo" - val bp = new BorderPanel { - layout(buttonPanel) = BorderPanel.Position.North - layout(logScrollPane) = BorderPanel.Position.Center - } - contents = bp - listenTo(openButton) - listenTo(saveButton) - val prefix = "You typed \"" - reactions += { - case ButtonClicked(`openButton`) => - if (fc.showOpenDialog(buttonPanel) == FileChooser.Result.Approve) { + layout(buttonPanel) = BorderPanel.Position.North + layout(logScrollPane) = BorderPanel.Position.Center + + listenTo(openButton) + listenTo(saveButton) + + reactions += { + case ButtonClicked(`openButton`) => + fc.showOpenDialog(buttonPanel) match { + case FileChooser.Result.Approve => val file: File = fc.selectedFile //This is where a real application would open the file. - log.append("Opening: " + file.getName() + "." + newline) - } - else { - log.append("Open command cancelled by user." + newline) - } - case ButtonClicked(`saveButton`) => - if (fc.showOpenDialog(buttonPanel) == FileChooser.Result.Approve) { + log.append(s"Opening: ${file.getName}.\n" ) + case _ => + log.append("Open command cancelled by user.\n") + } + + + case ButtonClicked(`saveButton`) => + fc.showSaveDialog(buttonPanel) match { + case FileChooser.Result.Approve => val file: File = fc.selectedFile //This is where a real application would save the file. - log.append("Saving: " + file.getName() + "." + newline) - } - else { - log.append("Save command cancelled by user." + newline) - } - } + log.append(s"Saving: ${file.getName}.\n") + case _ => + log.append("Save command cancelled by user.\n") + } } +} + +object FileChooserDemo extends SimpleSwingApplication { + def createImageIcon(path: String ): Option[javax.swing.ImageIcon] = + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + + lazy val top = new MainFrame() { + title = "FileChooserDemo" + //Create and set up the content pane. + contents = new FileChooserDemo() + } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala index 5a97cc83..def31c4e 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/HtmlDemo.scala @@ -62,8 +62,7 @@ class HtmlDemo extends BoxPanel(Orientation.Horizontal) { val scrollPane = new ScrollPane(htmlTextArea) val changeTheLabel = new Button("Change the label") { mnemonic = Key.C - // peer.setAlignmentX(Component.CENTER_ALIGNMENT) - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = Component.CENTER_ALIGNMENT } val theLabel = new Label(initialText) { minimumSize = new Dimension(200, 200) @@ -101,6 +100,6 @@ object HtmlDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "HtmlDemo" //Create and set up the content pane. - contents = new HtmlDemo(); + contents = new HtmlDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index 914c9583..b67aa546 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -31,10 +31,9 @@ package scala.swing.examples.tutorials.components import scala.swing._ -import java.net.URL import java.awt.RenderingHints import java.awt.image.BufferedImage -import javax.swing.{ Icon, ImageIcon, JToolBar, SwingWorker } +import javax.swing.{ Icon, ImageIcon } /** * Tutorial: How to Use Icons @@ -64,7 +63,6 @@ import javax.swing.{ Icon, ImageIcon, JToolBar, SwingWorker } * /scala/swing/examples/tutorials/images/sunw05.jpg
* * @author Collin Fagan - * @date 7/25/2007 * @version 2.0 */ class IconDemoApp extends MainFrame { @@ -76,7 +74,7 @@ class IconDemoApp extends MainFrame { * List of all the descriptions of the image files. These correspond one to * one with the image file names */ - private val imageFileNames = Array[String]("sunw01.jpg", "sunw02.jpg", + private val imageFileNames = Array[String]( "sunw01.jpg", "sunw02.jpg", "sunw03.jpg", "sunw04.jpg", "sunw05.jpg") private val imageCaptions = Array[String]("Original SUNW Logo", "The Clocktower", @@ -106,63 +104,37 @@ class IconDemoApp extends MainFrame { // this centers the frame on the screen // setLocationRelativeTo(null) - // start the image loading SwingWorker in a background thread - loadImages.execute() + def loadImage( fileName:String, caption: String ): Option[ThumbnailAction] = { + IconDemoApp.createImageIcon(imagedir + fileName) match { + case Some(img) => + val thumbnailIcon = new ImageIcon(getScaledImage(img.getImage, 32, 32)) + Some(new ThumbnailAction(img, thumbnailIcon, caption, photographLabel)) + case None => + Some(new ThumbnailAction(placeholderIcon, placeholderIcon, caption, photographLabel)) + } + } - /** - * SwingWorker class that loads the images a background thread and calls publish - * when a new one is ready to be displayed. - * - * We use Unit as the first SwingWroker param as we do not need to return - * anything from doInBackground(). - */ - def loadImages(): SwingWorker[Unit, ThumbnailAction] = - new SwingWorker[Unit, ThumbnailAction]() { - /** - * Creates full size and thumbnail versions of the target image files. - */ - override protected def doInBackground(): Unit = { - println("doInBackground") - for (i <- 0 until imageCaptions.length) { - val iconOption: Option[ImageIcon] = IconDemoApp.createImageIcon(imagedir + imageFileNames(i), imageCaptions(i)) - - val thumbAction: ThumbnailAction = - if (iconOption.isDefined) { - val thumbnailIcon: ImageIcon = new ImageIcon(getScaledImage(iconOption.get.getImage(), 32, 32)) - new ThumbnailAction(iconOption.get, thumbnailIcon, imageCaptions(i)) - } else { - // the image failed to load for some reason - // so load a placeholder instead - new ThumbnailAction(placeholderIcon, placeholderIcon, imageCaptions(i)) - } - publish(thumbAction); - } - } - - /** - * Process all loaded images. - */ - override def process(chunks: java.util.List[ThumbnailAction]): Unit = { - println("process") - val it: java.util.Iterator[ThumbnailAction] = chunks.iterator() - while (it.hasNext()) { - val thumbAction = it.next() - val thumbButton = new Button(thumbAction); - // add the new button BEFORE the last glue - // this centers the buttons in the toolbar - buttonBar.contents.dropRight(1) - buttonBar.contents += new Button(thumbAction) - buttonBar.contents += Swing.Glue + import scala.concurrent._ + import scala.concurrent.ExecutionContext.Implicits.global + + val f:Future[List[Option[ThumbnailAction]]] = Future { + imageCaptions.zip(imageFileNames).map { + case (cap, file) => loadImage(file, cap) + }.toList + } + + f.onSuccess{ + case thumbs:List[Option[ThumbnailAction]] => + buttonBar.contents.dropRight(1) + thumbs.foreach{ thumbAction => { + thumbAction.foreach { ta => + buttonBar.contents += new Button(ta) } - } - - /** - * Done. - */ - override def done(): Unit = { - println("Done") - } - } + }} + buttonBar.contents += Swing.Glue + + } + /** * Resizes an image using a Graphics2D object backed by a BufferedImage. @@ -173,47 +145,41 @@ class IconDemoApp extends MainFrame { */ private def getScaledImage(srcImg: Image, w: Int, h: Int): Image = { val resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) - val g2: Graphics2D = resizedImg.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g2.drawImage(srcImg, 0, 0, w, h, null); - g2.dispose(); - resizedImg; + val g2: Graphics2D = resizedImg.createGraphics() + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) + g2.drawImage(srcImg, 0, 0, w, h, null) + g2.dispose() + resizedImg } } object IconDemoApp extends SimpleSwingApplication { - def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { - val icon = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - if (icon.isDefined) { icon.get.setDescription(description); icon } else None + + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) } lazy val top = new IconDemoApp() { - title = "IconDemoApp" + title = "Icon Demo: Please Select an Image" } } /** - * @param Icon - The full size photo to show in the button. - * @param Icon - The thumbnail to show in the button. - * @param String - The description of the icon. + * @param photo - The full size photo to show in the button. + * @param thumb - The thumbnail to show in the button. + * @param desc - The description of the icon. */ -class ThumbnailAction(photo: Icon, thumb: Icon, desc: String) extends Action(desc) { - /** - * The icon if the full image we want to display. - */ - private val displayPhoto: Icon = photo - - // The LARGE_ICON_KEY is the key for setting the +class ThumbnailAction(photo: Icon, thumb: Icon, desc: String, photographLabel:Label) extends Action("") { // icon when an Action is applied to a butt - peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, desc) + toolTip = desc // The short description becomes the tooltip of a button. - peer.putValue(javax.swing.Action.LARGE_ICON_KEY, thumb) + icon = thumb - def apply() {} + def apply(): Unit = { + photographLabel.icon = photo + IconDemoApp.top.title = s"Icon Demo: $desc" + } } -class ToolBar extends scala.swing.Component with SequentialContainer.Wrapper { - override lazy val peer: JToolBar = new JToolBar with SuperMixin -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala index 21c3dc81..65e7c454 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MissingIcon.scala @@ -44,7 +44,6 @@ import javax.swing.Icon * icon from an external location. * * @author Collin Fagan - * @date 7/25/2007 */ class MissingIcon extends Icon { @@ -71,12 +70,8 @@ class MissingIcon extends Icon { g2d.dispose() } - def getIconWidth(): Int = { - width - } + override def getIconWidth: Int = width - def getIconHeight(): Int = { - height - } + override def getIconHeight: Int = height } \ No newline at end of file From 4ae018554d5086461e93be6757aeab882fc8742d Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 3 Oct 2014 16:37:27 -0700 Subject: [PATCH 31/36] Use javax.swing.Component constants when assigning to xLayoutAlignment. --- .../swing/examples/tutorials/components/FrameDemo2.scala | 3 +-- .../swing/examples/tutorials/components/ListDialog.scala | 7 +------ .../examples/tutorials/components/ListDialogRunner.scala | 6 +++--- .../swing/examples/tutorials/components/SliderDemo.scala | 4 ++-- .../swing/examples/tutorials/components/SliderDemo2.scala | 2 +- .../examples/tutorials/components/TablePrintDemo.scala | 2 +- 6 files changed, 9 insertions(+), 15 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index a47ec307..3b645ad7 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -246,8 +246,7 @@ class MyFrame extends Frame { contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.PAGE_AXIS)) contentPane.add(Box.createVerticalGlue()) // takes all extra space contentPane.add(button.peer) - // button.peer.setAlignmentX(Component.CENTER_ALIGNMENT) //horizontally centered - button.xLayoutAlignment = 0.50 // Center + button.xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT contentPane.add(Box.createVerticalStrut(5)) //spacer // listenTo(button) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala index 8e40c66d..b332e978 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala @@ -74,15 +74,13 @@ class ListDialog(frame: Frame, locationComp: Component, } selection.intervalMode = ListView.IntervalMode.SingleInterval } - // Setting the selection mode of the peer does not have an effect. list.peer.setLayoutOrientation(javax.swing.JList.HORIZONTAL_WRAP) val lSelect = list.selection defaultButton = setButton // val listScroller = new ScrollPane(list) { preferredSize = new Dimension(250, 80) - // peer.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT) - xLayoutAlignment = 0.0 // Left + xLayoutAlignment = java.awt.Component.LEFT_ALIGNMENT } // //Create a container so that we can add a title around @@ -117,9 +115,6 @@ class ListDialog(frame: Frame, locationComp: Component, listenTo(cancelButton) listenTo(list.mouse.clicks) // listenTo(list.selection) - //Getting the selections out of the ListView is problematic. I can't figure out a way to get - //it to work. There are no demos available that use ListViews and actually consume the choices - //made with the list. Maybe it is a broken component? reactions += { case ButtonClicked(`setButton`) => setValue(list.listData(list.selection.leadIndex)) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala index 09ffe4f2..12bfd27c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala @@ -50,19 +50,19 @@ class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) //Create the labels. val intro = new Label("The chosen name:") { - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } val nameLabel = new Label(names(1)) { //Use a wacky font if it exists. If not, this falls //back to a font we know exists. font = getAFont() - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } intro.peer.setLabelFor(nameLabel.peer) //Create the button. val button = new Button("Pick a new name...") { - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } contents += intro diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index 36fe76b0..60d3fad2 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -62,7 +62,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act val sliderLabel = new Label("Frames Per Second") { horizontalAlignment = Alignment.Center - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } val framesPerSecond = new Slider { @@ -81,7 +81,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act val picture = new Label() { horizontalAlignment = Alignment.Center - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT Swing.Lowered border = Swing.CompoundBorder( Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala index 491ff4bf..d3513173 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala @@ -81,7 +81,7 @@ class SliderDemo2(window: Window) extends BorderPanel with ActionListener { val picture = new Label() { horizontalAlignment = Alignment.Center - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT Swing.Lowered border = Swing.CompoundBorder( Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala index 9e0a2b89..93f4e9de 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala @@ -65,7 +65,7 @@ class TablePrintDemo extends BoxPanel(Orientation.Vertical) { //Add a print button. val printButton = new Button("Print") { // peer.setAlignmentX(0.5f) - xLayoutAlignment = 0.50 // Center + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } //Add the scroll pane to this panel. From 93f97aa5fd560291d15f03212d62b03d7c43c6ad Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Fri, 3 Oct 2014 16:39:35 -0700 Subject: [PATCH 32/36] Use repaint from scala.swing.UIElement instead of the repaint method of a peer. --- .../scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala index 62aecedb..325fba53 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala @@ -85,7 +85,7 @@ class FlowLayoutDemo extends BorderPanel { compsToExperiment.peer.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) } compsToExperiment.peer.validate() - compsToExperiment.peer.repaint() + compsToExperiment.repaint() } } From 3e5040b4b810e09c05261f9b120363ea434be085 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Sun, 5 Oct 2014 23:16:24 -0700 Subject: [PATCH 33/36] Merge with andy1138-tutorial. In the process, ListDemo's cancel button was fixed and some stray comments were removed. --- .../tutorials/images/scala-stairs.jpg | Bin 0 -> 325568 bytes .../tutorials/components/ButtonDemo.scala | 13 +- .../tutorials/components/ButtonHtmlDemo.scala | 21 +- .../tutorials/components/CheckboxDemo.scala | 7 +- .../tutorials/components/ComboBoxDemo.scala | 11 +- .../tutorials/components/ComboBoxDemo2.scala | 1 - .../components/CustomComboBoxDemo.scala | 7 +- .../tutorials/components/DialogDemo.scala | 5 +- .../components/FormattedTextFieldDemo.scala | 12 +- .../tutorials/components/FrameDemo2.scala | 33 +-- .../tutorials/components/IconDemoApp.scala | 6 +- .../tutorials/components/LabelDemo.scala | 11 +- .../tutorials/components/ListDemo.scala | 44 ++-- .../tutorials/components/ListDialog.scala | 120 +++++++-- .../components/ListDialogRunner.scala | 123 --------- .../tutorials/components/MenuDemo.scala | 15 +- .../tutorials/components/MenuGlueDemo.scala | 23 +- .../tutorials/components/MenuLookDemo.scala | 15 +- .../tutorials/components/PasswordDemo.scala | 81 +++--- .../tutorials/components/PopupMenuDemo.scala | 15 +- .../components/RadioButtonDemo.scala | 43 ++-- .../examples/tutorials/components/Rule.scala | 138 ----------- .../tutorials/components/ScrollDemo.scala | 233 +++++++++++++++--- .../tutorials/components/ScrollDemo2.scala | 6 +- .../components/ScrollablePicture.scala | 106 -------- .../components/SimpleTableDemo.scala | 13 +- .../components/SimpleTableSelectionDemo.scala | 28 +-- .../tutorials/components/SliderDemo.scala | 47 ++-- .../tutorials/components/SliderDemo2.scala | 186 -------------- .../tutorials/components/SplitPaneDemo.scala | 214 ++++++++-------- .../tutorials/components/SplitPaneDemo2.scala | 80 +++++- .../components/SplitPaneDividerDemo.scala | 12 +- 32 files changed, 701 insertions(+), 968 deletions(-) create mode 100644 examples/src/main/resources/scala/swing/examples/tutorials/images/scala-stairs.jpg delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala diff --git a/examples/src/main/resources/scala/swing/examples/tutorials/images/scala-stairs.jpg b/examples/src/main/resources/scala/swing/examples/tutorials/images/scala-stairs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5d6e3f78d453a8a9e531ac60849e2f1c95d0e9ab GIT binary patch literal 325568 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

  • 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%0AQ7!m6puuEz=cNcd%ZDf>qJNYK?t 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 z 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 Swing.Icon(imgURL)) - } - UIManager.put("swing.boldMetal", false) + lazy val top = new MainFrame() { title = "ButtonDemo" - //Create and set up the content pane. - contents = new ButtonDemo(); + javax.swing.UIManager.put("swing.boldMetal", false) + + contents = new ButtonDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala index 06fda6ec..cfe31595 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ButtonHtmlDemo.scala @@ -34,7 +34,7 @@ import scala.swing._ import scala.swing.event.ButtonClicked import java.awt.Font -/** +/* * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] * @@ -47,9 +47,9 @@ import java.awt.Font * /scala/swing/examples/tutorials/images/left.gif */ class ButtonHtmlDemo extends FlowPanel { - val leftButtonIcon = ButtonHtmlDemo.createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get - val middleButtonIcon = ButtonHtmlDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val rightButtonIcon = ButtonHtmlDemo.createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get + val leftButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/right.gif").get + val middleButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get + val rightButtonIcon = createImageIcon("/scala/swing/examples/tutorials/images/left.gif").get // val disable: Button = new Button("

    Disable
    " + "middle button") { @@ -102,12 +102,19 @@ class ButtonHtmlDemo extends FlowPanel { middle.enabled = false disable.enabled = false } + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + val imgURL: java.net.URL = getClass().getResource(path) + val img: Option[javax.swing.ImageIcon] = if (imgURL != null) { + Some(Swing.Icon(imgURL)) + } else { + None + } + img + } + } object ButtonHtmlDemo extends SimpleSwingApplication { - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } lazy val top = new MainFrame() { title = "ButtonHtmlDemo" //Create and set up the content pane. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala index 8b3a4f12..cae5f182 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CheckboxDemo.scala @@ -35,11 +35,10 @@ import scala.swing.event.ButtonClicked import scala.swing.event.Key import java.awt.Font -import scala.swing.examples.tutorials.components.ButtonDemo._ /** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/button.html * * Source code reference: * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CheckBoxDemoProject/src/components/CheckBoxDemo.java]] @@ -50,7 +49,7 @@ import scala.swing.examples.tutorials.components.ButtonDemo._ * geek-cg--.gif, ..., geek-cght.gif. */ class CheckboxDemo extends BorderPanel { - /* + /** * Four accessory choices provide for 16 different * combinations. The image for each combination is * contained in a separate image file whose name indicates @@ -146,7 +145,7 @@ class CheckboxDemo extends BorderPanel { pictureLabel.tooltip = choices.toString //Get the icon corresponding to the image. - createImageIcon( s"/scala/swing/examples/tutorials/images/geek/geek-$choices.gif") match { + CheckboxDemo.createImageIcon( s"/scala/swing/examples/tutorials/images/geek/geek-$choices.gif") match { case Some( icon ) => pictureLabel.icon = icon pictureLabel.text = null diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala index 840f1350..c24e24bb 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo.scala @@ -36,13 +36,12 @@ import scala.swing.event.SelectionChanged import java.awt.{ Dimension, Font } import javax.swing.BorderFactory - -/** +/* * Tutorial: How to Use Combo Boxes * [[http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html]] * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemoProject/src/components/ComboBoxDemo.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ComboBoxDemoProject/src/components/ComboBoxDemo.java */ class ComboBoxDemo extends BorderPanel { @@ -78,14 +77,14 @@ class ComboBoxDemo extends BorderPanel { } def updateLabel(s: String): Unit = { - picture.icon = - ComboBoxDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + s + ".gif").getOrElse( Swing.EmptyIcon ) + val ic = ComboBoxDemo.createImageIcon(s"/scala/swing/examples/tutorials/images/$s.gif") + picture.icon = imgIcon.getOrElse( Swing.EmptyIcon ) } } object ComboBoxDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ + /** Returns an ImageIcon, or null if the path was invalid. */ def createImageIcon(path: String ): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala index eb65b45b..da38684b 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ComboBoxDemo2.scala @@ -66,7 +66,6 @@ class ComboBoxDemo2 extends BoxPanel(Orientation.Vertical) { val patternList = new ComboBox[String](patternExamples) { makeEditable() selection.item = patternExamples(0) - xLayoutAlignment = 0.0 // Left } //Create the UI for displaying result. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala index 27687ce9..fc5339e4 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala @@ -33,6 +33,7 @@ package scala.swing.examples.tutorials.components import scala.swing._ import javax.swing.ImageIcon +import java.net.URL import java.awt.{ Dimension, Font } /** @@ -109,11 +110,9 @@ class CustomComboBoxDemo extends BorderPanel { object CustomComboBoxDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } - + lazy val top = new MainFrame() { title = "CustomComboBoxDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala index 2d45907f..75c6355f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala @@ -380,11 +380,8 @@ class DialogDemo(val frame: Frame) extends BorderPanel { } object DialogDemo extends SimpleSwingApplication { - - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } lazy val top = new MainFrame() { title = "DialogDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala index 5674e58f..c7374338 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala @@ -33,14 +33,13 @@ package scala.swing.examples.tutorials.components import scala.swing._ import java.text.NumberFormat import java.awt.Color -import javax.swing.UIManager -/** +/* * Tutorial: How to Use Formatted Text Fields - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FormattedTextFieldDemoProject/src/components/FormattedTextFieldDemo.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FormattedTextFieldDemoProject/src/components/FormattedTextFieldDemo.java * * FormattedTextFieldDemo.scala requires no other files. * @@ -162,10 +161,11 @@ class FormattedTextFieldDemo extends BorderPanel { } object FormattedTextFieldDemo extends SimpleSwingApplication { - UIManager.put("swing.boldMetal", false) lazy val top = new MainFrame() { title = "FormattedTextFieldDemo" //Create and set up the content pane. - contents = new FormattedTextFieldDemo() + javax.swing.UIManager.put("swing.boldMetal", false) + contents = new FormattedTextFieldDemo(); } + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index 3b645ad7..0b5ec75f 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -37,12 +37,12 @@ import java.awt.{ BorderLayout, Color, Component, Dimension, Graphics, Image, Po import java.awt.image.BufferedImage import java.net.URL -/** +/* * Tutorial: How to Make Frames (Main Windows) - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemo2Project/src/components/FrameDemo2.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemo2Project/src/components/FrameDemo2.java * * FrameDemo2.scala shows off the window decoration features added in * 1.4, plus some window positioning code and (optionally) @@ -264,18 +264,6 @@ class MyFrame extends Frame { } object FrameDemo2 extends SimpleSwingApplication { - //Use the Java look and feel. This needs to be done before the frame is created - //so the companion object FrameDemo2 cannot simply extend SimpleSwingApplcation. - try { - UIManager.setLookAndFeel( - UIManager.getCrossPlatformLookAndFeelClassName()); - } catch { - case e: Exception => ; - } - //Make sure we have nice window decorations. - JFrame.setDefaultLookAndFeelDecorated(true); - JDialog.setDefaultLookAndFeelDecorated(true); - //Creates an icon-worthy Image from scratch. def createFDImage(): Image = { //Create a 16x16 pixel image. @@ -306,13 +294,26 @@ object FrameDemo2 extends SimpleSwingApplication { lazy val top = new Frame() { title = "FrameDemo2" + //Use the Java look and feel. This needs to be done before the frame is created + //so the companion object FrameDemo2 cannot simply extend SimpleSwingApplcation. + try { + UIManager.setLookAndFeel( + UIManager.getCrossPlatformLookAndFeelClassName()); + } catch { + case e: Exception => ; + } + //Make sure we have nice window decorations. + JFrame.setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); //Create and set up the content pane. val demo = new FrameDemo2(); //Add components to it. val contentPane = peer.getContentPane() + } top.contentPane.add(top.demo.createOptionControls(top), BorderLayout.CENTER) top.contentPane.add(top.demo.createButtonPane(top), BorderLayout.PAGE_END) -} \ No newline at end of file + javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala index b67aa546..47ca7803 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/IconDemoApp.scala @@ -154,11 +154,9 @@ class IconDemoApp extends MainFrame { } object IconDemoApp extends SimpleSwingApplication { - - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } - + lazy val top = new IconDemoApp() { title = "Icon Demo: Please Select an Image" } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala index 5fd5d1e1..2b8f0d72 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/LabelDemo.scala @@ -32,7 +32,6 @@ package scala.swing.examples.tutorials.components import scala.swing._ import javax.swing.ImageIcon -import java.net.URL import javax.swing.UIManager /** @@ -72,13 +71,13 @@ class LabelDemo extends GridPanel(3, 1) { object LabelDemo extends SimpleSwingApplication { UIManager.put("swing.boldMetal", false) /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { - val icon = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - if (icon.isDefined) { icon.get.setDescription(description); icon } else None - } + def createImageIcon(path: String, desc:String ): Option[javax.swing.ImageIcon] = + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + lazy val top = new MainFrame() { title = "LabelDemo" //Create and set up the content pane. - contents = new LabelDemo(); + javax.swing.UIManager.put("swing.boldMetal", false) + contents = new LabelDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala index 53dff67d..9f054015 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDemo.scala @@ -45,8 +45,6 @@ import java.awt.Toolkit * ListDemo.scala requires no other files. */ class ListDemo extends BorderPanel { - private val hireString = "Hire" - private val fireString = "Fire" private val listModel: Array[String] = Array("Jane Doe", "John Smith", "Kathy Green") @@ -59,13 +57,20 @@ class ListDemo extends BorderPanel { } val listScrollPane: ScrollPane = new ScrollPane(listMe) - val hireButton: Button = new Button(hireString) { + + val hireButton: Button = new Button("Hire") { enabled = false - // actionCommand = hireString + reactions += { + case ButtonClicked(_) => hireListenerMethod() + } } - val fireButton: Button = new Button(fireString) { - // actionComand = fireString + + val fireButton: Button = new Button("Fire") { + reactions += { + case ButtonClicked(_) => fireListenerMethod() + } } + val employeeName: TextField = new TextField(10) // employeeName.peer.getDocument().addDocumentListener(hireListener); val nameSelected: String = listModel(initiallySelected) @@ -87,28 +92,22 @@ class ListDemo extends BorderPanel { layout(buttonPane) = BorderPanel.Position.South listenTo(listMe.selection) - listenTo(fireButton) listenTo(employeeName) - listenTo(hireButton) reactions += { - case ButtonClicked(`fireButton`) => - fireListenerMethod() case EditDone(`employeeName`) => hireListenerMethod() - case ButtonClicked(`hireButton`) => - hireListenerMethod() case SelectionChanged(`listMe`) => fireButton.enabled = listMe.selection.leadIndex >= 0 case ValueChanged(`employeeName`) => hireButton.enabled = employeeName.text.trim().length > 0 } + //This method tests for string equality. You could certainly //get more sophisticated about the algorithm. For example, //you might want to ignore white space and capitalization. - def alreadyInList(name: String): Boolean = { - listMe.listData.contains(name); - } + def alreadyInList(name: String): Boolean = listMe.listData.contains(name) + def fireListenerMethod(): Unit = { //This method can be called only if //there's a valid selection @@ -126,24 +125,19 @@ class ListDemo extends BorderPanel { //removed item in last position index -= 1 } - listMe.selectIndices(index); - listMe.ensureIndexIsVisible(index); + listMe.selectIndices(index) + listMe.ensureIndexIsVisible(index) } } def hireListenerMethod(): Unit = { val nameSelected: String = employeeName.text //User didn't type in a unique name... if (nameSelected.equals("") || alreadyInList(nameSelected)) { - Toolkit.getDefaultToolkit().beep() + Toolkit.getDefaultToolkit.beep() employeeName.requestFocusInWindow() employeeName.selectAll() } else { - var index: Int = listMe.selection.leadIndex //get selected index - if (index == -1) { //no selection, so insert at beginning - index = 0 - } else { //add after the selected item - index += 1 - } + val index: Int = listMe.selection.leadIndex + 1 //get selected index val (x: Seq[String], y: Seq[String]) = listMe.listData.splitAt(index) val z = employeeName.text +: y @@ -166,6 +160,6 @@ object ListDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "ListDemo" //Create and set up the content pane. - contents = new ListDemo(); + contents = new ListDemo() } } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala index b332e978..90a0b7ab 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala @@ -29,7 +29,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package scala.swing.examples.tutorials.components -import java.awt.{Dimension, GraphicsConfiguration, Point} + +import java.awt.Dimension +import java.awt.Font +import java.awt.Point +import java.awt._ +import scala.swing.Button +import scala.swing.Component +import scala.swing.Dialog +import scala.swing.Frame +import scala.swing.Label +import scala.swing.ScrollPane import scala.swing._ import scala.swing.event.{ButtonClicked, Key, MouseClicked} @@ -57,10 +67,9 @@ import scala.swing.event.{ButtonClicked, Key, MouseClicked} * */ class ListDialog(frame: Frame, locationComp: Component, - labelText: String, title: String, data: Array[String], - initialValue: String, longValue: String) extends Dialog( - frame: Window, - frame.peer.getGraphicsConfiguration: GraphicsConfiguration) { + labelText: String, title: String, data: Array[String], + initialValue: String, longValue: String) extends Dialog( frame, frame.peer.getGraphicsConfiguration) { + // Must be a modal dialog. Otherwise the showDialog call will return // immediately and the value returned will not reflect the user's // selections. @@ -75,6 +84,7 @@ class ListDialog(frame: Frame, locationComp: Component, selection.intervalMode = ListView.IntervalMode.SingleInterval } list.peer.setLayoutOrientation(javax.swing.JList.HORIZONTAL_WRAP) + val lSelect = list.selection defaultButton = setButton // @@ -110,23 +120,20 @@ class ListDialog(frame: Frame, locationComp: Component, //Initialize values. setValue(initialValue) + // Events listenTo(setButton) listenTo(cancelButton) listenTo(list.mouse.clicks) -// listenTo(list.selection) reactions += { case ButtonClicked(`setButton`) => setValue(list.listData(list.selection.leadIndex)) visible = false - case ButtonClicked(`cancelButton`) => + case ButtonClicked(`cancelButton`) => setValue(initialValue) visible = false -// case SelectionChanged(`list`) => -// println("SelectionChanged") -// println(list.selection.leadIndex) case MouseClicked(source: Component, point: Point, modifiers: Key.Modifiers, - clicks: Int, triggersPopup: Boolean) => if (clicks == 2) setButton.doClick + clicks: Int, triggersPopup: Boolean) => if (clicks == 2) setButton.doClick() } // pack() @@ -151,14 +158,95 @@ object ListDialog { * dialog should appear. */ def showDialog(frameComp: Frame, locationComp: Component, - labelText: String, - title: String, - possibleValues: Array[String], - initialValue: String, - longValue: String): String = { + labelText: String, + title: String, + possibleValues: Array[String], + initialValue: String, + longValue: String): String = { val dialog = new ListDialog(frameComp, locationComp, labelText, title, possibleValues, initialValue, longValue) dialog.visible = true value } } + + +class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) { + val names: Array[String] = Array("Arlo", "Cosmo", "Elmo", "Hugo", + "Jethro", "Laszlo", "Milo", "Nemo", + "Otto", "Ringo", "Rocco", "Rollo") + + //Create the labels. + val intro = new Label("The chosen name:") + val nameLabel = new Label(names(1)) { + //Use a wacky font if it exists. If not, this falls + //back to a font we know exists. + font = getAFont + } + intro.peer.setLabelFor(nameLabel.peer) + + //Create the button. + val button = new Button("Pick a new name...") { + + } + + listenTo(button) + reactions += { + case ButtonClicked(`button`) => + nameLabel.text = ListDialog.showDialog( + frame, + button, + "Baby names ending in 0:", + "Name chooser", + names.asInstanceOf[Array[String]], + nameLabel.text, + "Cosmo ") + + + } + + + contents += intro + contents += nameLabel + contents += button + + + def getAFont: Font = { + //initial strings of desired fonts + val desiredFonts = Array[String]("French Script", "FrenchScript", "Bitstream Vera Sans") + //Search for all installed font families. The first + //call may take a while on some systems with hundreds of + //installed fonts, so if possible execute it in idle time, + //and certainly not in a place that delays painting of + //the UI (for example, when bringing up a menu). + // + //In systems with malformed fonts, this code might cause + //serious problems; use the latest JRE in this case. (You'll + //see the same problems if you use Swing's HTML support or + //anything else that searches for all fonts.) If this call + //causes problems for you under the latest JRE, please let + //us know. + val gEnv: GraphicsEnvironment = + GraphicsEnvironment.getLocalGraphicsEnvironment + val existingFamilyNames: Array[String] = gEnv.getAvailableFontFamilyNames + val chosenFonts: Array[Font] = + for { + desiredFont <- desiredFonts + existingFamilyName <- existingFamilyNames + if existingFamilyName.startsWith(desiredFont) + } yield new Font(existingFamilyName, Font.PLAIN, 30) + if (chosenFonts.nonEmpty) { + chosenFonts(0) + } else { + new Font("Serif", Font.ITALIC, 36) + } + } +} + +object ListDialogRunner extends SimpleSwingApplication { + lazy val top = new MainFrame() { + title = "Name That Baby" + //Create and set up the content pane. + contents = new ListDialogRunner(this) + } +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala deleted file mode 100644 index 12bfd27c..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialogRunner.scala +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import java.awt.Font -import java.awt.GraphicsEnvironment -import scala.swing._ -import scala.swing.event.ButtonClicked - -/** - * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java]] - */ -class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) { - val names: Array[String] = Array("Arlo", "Cosmo", "Elmo", "Hugo", - "Jethro", "Laszlo", "Milo", "Nemo", - "Otto", "Ringo", "Rocco", "Rollo") - - //Create the labels. - val intro = new Label("The chosen name:") { - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - val nameLabel = new Label(names(1)) { - //Use a wacky font if it exists. If not, this falls - //back to a font we know exists. - font = getAFont() - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - intro.peer.setLabelFor(nameLabel.peer) - - //Create the button. - val button = new Button("Pick a new name...") { - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - - contents += intro - contents += nameLabel - contents += button - - listenTo(button) - reactions += { - case ButtonClicked(`button`) => - nameLabel.text = ListDialog.showDialog( - frame, - button, - "Baby names ending in 0:", - "Name chooser", - names.asInstanceOf[Array[String]], - nameLabel.text, - "Cosmo ") - } - - def getAFont(): Font = { - //initial strings of desired fonts - val desiredFonts = Array[String]("French Script", "FrenchScript", "Bitstream Vera Sans") - //Search for all installed font families. The first - //call may take a while on some systems with hundreds of - //installed fonts, so if possible execute it in idle time, - //and certainly not in a place that delays painting of - //the UI (for example, when bringing up a menu). - // - //In systems with malformed fonts, this code might cause - //serious problems; use the latest JRE in this case. (You'll - //see the same problems if you use Swing's HTML support or - //anything else that searches for all fonts.) If this call - //causes problems for you under the latest JRE, please let - //us know. - val gEnv: GraphicsEnvironment = - GraphicsEnvironment.getLocalGraphicsEnvironment - val existingFamilyNames: Array[String] = gEnv.getAvailableFontFamilyNames - val chosenFonts: Array[Font] = - for { - desiredFont <- desiredFonts - existingFamilyName <- existingFamilyNames - if existingFamilyName.startsWith(desiredFont) - } yield new Font(existingFamilyName, Font.PLAIN, 30) - if (chosenFonts.length > 0) { - chosenFonts(0) - } else { - new Font("Serif", Font.ITALIC, 36) - } - } -} - -object ListDialogRunner extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "Name That Baby" - //Create and set up the content pane. - contents = new ListDialogRunner(this); - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala index c056df2f..78fc113c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala @@ -36,12 +36,12 @@ import java.net.URL import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } -/** +/* * Tutorial: How to Use Menus - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java * * MenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. * @@ -201,8 +201,13 @@ class MenuDemo extends BorderPanel { object MenuDemo extends SimpleSwingApplication { /** Returns an ImageIcon icon, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + def createImageIcon(path: String): Option[ImageIcon] = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Some(Swing.Icon(imgURL)) + } else { + None + } } lazy val top = new MainFrame() { title = "MenuDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala index 4f2a222a..65fc0c9c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuGlueDemo.scala @@ -45,23 +45,22 @@ import scala.swing._ * @author ges * @author kwalrath */ -/* MenuGlueDemo.scala requires no other files. */ class MenuGlueDemo extends MainFrame { def createMenuBar(): MenuBar = { - val menuBar = new MenuBar(); - menuBar.contents += createMenu("Menu 1") - menuBar.contents += createMenu("Menu 2") - menuBar.contents += Swing.HGlue - menuBar.contents += createMenu("Menu 3") - menuBar; + new MenuBar() { + contents += createMenu("Menu 1") + contents += createMenu("Menu 2") + contents += Swing.HGlue + contents += createMenu("Menu 3") + } } def createMenu(title: String): Menu = { - val m = new Menu(title); - m.contents += new MenuItem("Menu item #1 in " + title) - m.contents += new MenuItem("Menu item #2 in " + title) - m.contents += new MenuItem("Menu item #3 in " + title) - m; + new Menu(title) { + contents += new MenuItem(s"Menu item #1 in $title") + contents += new MenuItem(s"Menu item #2 in $title") + contents += new MenuItem(s"Menu item #3 in $title") + } } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala index ed0b0524..5b6f81fc 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala @@ -36,12 +36,12 @@ import java.net.URL import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } -/** +/* * Tutorial: How to Use Menus - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuLookDemoProject/src/components/MenuLookDemo.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuLookDemoProject/src/components/MenuLookDemo.java * * MenuLookDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. * @@ -171,8 +171,13 @@ class MenuLookDemo extends BorderPanel { object MenuLookDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + def createImageIcon(path: String): Option[ImageIcon] = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Some(Swing.Icon(imgURL)) + } else { + None + } } lazy val top = new MainFrame() { diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala index 43db934b..326b98a1 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PasswordDemo.scala @@ -12,54 +12,53 @@ import scala.swing._ * PasswordDemo.scala requires no other files. */ class PasswordDemo(val controllingFrame: Frame) extends FlowPanel { - private val OK = "ok" - private val Help = "help" val passwordField = new PasswordField(10) val label = new Label("Enter the password: ") - label.peer.setLabelFor(passwordField.peer) +// label.peer.setLabelFor(passwordField.peer) val buttonPane = createButtonPanel() - val textPane = new FlowPanel() - textPane.contents += label - textPane.contents += passwordField - // - contents += textPane - contents += buttonPane + val textPane = new FlowPanel() { + contents += label + contents += passwordField + } def createButtonPanel(): GridPanel = { - val p = new GridPanel(0, 1) - val okButton = new Button(Action("OK") { - val input: Array[Char] = passwordField.password - if (PasswordDemo.isPasswordCorrect(input)) { - Dialog.showMessage(p, - "Success! You typed the right password.", - "Passord Success", Dialog.Message.Info, Swing.EmptyIcon) - } else { - Dialog.showMessage(p, - "Invalid password. Try again.", - "Error Message", - Dialog.Message.Error, Swing.EmptyIcon) - } - //Zero out the possible password, for security. - for (i <- 0 until input.length) { - input(i) = '0' - } - passwordField.selectAll() - passwordField.requestFocusInWindow() - }) - val helpButton = new Button(Action("Help") { - Dialog.showMessage(p, + new GridPanel(0, 1) { + val okButton = new Button(Action("OK") { + val input: Array[Char] = passwordField.password + if (PasswordDemo.isPasswordCorrect(input)) { + Dialog.showMessage(this, + "Success! You typed the right password.", + "Passord Success", Dialog.Message.Info, Swing.EmptyIcon) + } else { + Dialog.showMessage(this, + "Invalid password. Try again.", + "Error Message", + Dialog.Message.Error, Swing.EmptyIcon) + } + //Zero out the possible password, for security. + for (i <- 0 until input.length) { + input(i) = '0' + } + passwordField.selectAll() + passwordField.requestFocusInWindow() + }) + + val helpButton = new Button(Action("Help") { + Dialog.showMessage(this, "You can get the password by searching this example's\n" - + "source code for the string \"correctPassword\".\n" - + "Or look at the section How to Use Password Fields in\n" - + "the components section of The Java Tutorial.", + + "source code for the string \"correctPassword\".\n" + + "Or look at the section How to Use Password Fields in\n" + + "the components section of The Java Tutorial.", "Passord Help", Dialog.Message.Info, Swing.EmptyIcon) - }) - p.contents += okButton - p.contents += helpButton - listenTo(okButton) - listenTo(helpButton) - p + }) + + contents += okButton + contents += helpButton + + listenTo(okButton) + listenTo(helpButton) + } } } @@ -77,7 +76,7 @@ object PasswordDemo extends SimpleSwingApplication { // Arrays.fill(correctPassword,'0'); for (i <- 0 until correctPassword.length) correctPassword.update(i, '0') - isCorrect; + isCorrect } lazy val top = new MainFrame() { title = "PasswordDemo" diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala index e1b0740b..d635e0ee 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala @@ -38,12 +38,12 @@ import javax.swing.{ ImageIcon, KeyStroke } import java.awt.event.{ ActionEvent, KeyEvent } import java.awt.Point -/** +/* * Tutorial: How to Use Password Fields - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html * * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PopupMenuDemoProject/src/components/PopupMenuDemo.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PopupMenuDemoProject/src/components/PopupMenuDemo.java * * PopupMenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. * @@ -237,8 +237,13 @@ class PopupMenuDemo extends BorderPanel { object PopupMenuDemo extends SimpleSwingApplication { /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + def createImageIcon(path: String): Option[ImageIcon] = { + val imgURL: URL = getClass().getResource(path) + if (imgURL != null) { + Some(Swing.Icon(imgURL)) + } else { + None + } } /** * Create the GUI and show it. diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala index 275abe13..28b30166 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/RadioButtonDemo.scala @@ -35,7 +35,6 @@ import java.awt.Dimension import scala.swing._ import scala.swing.event.{ ButtonClicked, Key } import javax.swing.ImageIcon -import java.net.URL /** * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons @@ -52,25 +51,30 @@ import java.net.URL * /scala/swing/examples/tutorials/images/Pig.gif */ class RadioButtonDemo extends BorderPanel { + val birdString = "Bird" + val catString = "Cat" + val dogString = "Dog" + val rabbitString = "Rabbit" + val pigString = "Pig" //Create the radio buttons. - val birdButton = new RadioButton(RadioButtonDemo.birdString) { + val birdButton = new RadioButton(birdString) { mnemonic = Key.B selected = true } - val catButton = new RadioButton(RadioButtonDemo.catString) { + val catButton = new RadioButton(catString) { mnemonic = Key.C selected = false } - val dogButton = new RadioButton(RadioButtonDemo.dogString) { + val dogButton = new RadioButton(dogString) { mnemonic = Key.D selected = false } - val rabbitButton = new RadioButton(RadioButtonDemo.rabbitString) { + val rabbitButton = new RadioButton(rabbitString) { mnemonic = Key.R selected = false } - val pigButton = new RadioButton(RadioButtonDemo.pigString) { + val pigButton = new RadioButton(pigString) { mnemonic = Key.P selected = false } @@ -81,9 +85,7 @@ class RadioButtonDemo extends BorderPanel { } //Set up the picture label. - val imgIcon = RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" - + RadioButtonDemo.birdString - + ".gif") + val imgIcon = RadioButtonDemo.createImageIcon(s"/scala/swing/examples/tutorials/images/$birdString.gif") val picture = new Label() { icon = imgIcon.get //The preferred size is hard-coded to be the width of the @@ -108,34 +110,19 @@ class RadioButtonDemo extends BorderPanel { listenTo(pigButton) reactions += { - case ButtonClicked(`birdButton`) => - picture.icon = getPictureIcon(RadioButtonDemo.birdString) - case ButtonClicked(`catButton`) => - picture.icon = getPictureIcon(RadioButtonDemo.catString) - case ButtonClicked(`dogButton`) => - picture.icon = getPictureIcon(RadioButtonDemo.dogString) - case ButtonClicked(`rabbitButton`) => - picture.icon = getPictureIcon(RadioButtonDemo.rabbitString) - case ButtonClicked(`pigButton`) => - picture.icon = getPictureIcon(RadioButtonDemo.pigString) + case ButtonClicked(button) => picture.icon = getPictureIcon(button.text) } - + def getPictureIcon(gifName: String): ImageIcon = { RadioButtonDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + gifName + ".gif").get } } object RadioButtonDemo extends SimpleSwingApplication { - val birdString = "Bird" - val catString = "Cat" - val dogString = "Dog" - val rabbitString = "Rabbit" - val pigString = "Pig" - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } + lazy val top = new MainFrame() { title = "RadioButtonDemo" contents = new RadioButtonDemo() diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala deleted file mode 100644 index 4a8d1e80..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/Rule.scala +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import java.awt.{ Color, Font, Graphics, Toolkit } - -class Rule(val orientation: Int, var isMetric: Boolean) extends Component { - val Inch: Int = Toolkit.getDefaultToolkit().getScreenResolution() - val Size = 35 - var units = if (isMetric) { - // dots per centimeter - (Inch.toDouble / 2.54).toInt - } else { - Inch - } - var increment = if (isMetric) { units } else { units / 2 } - def setIsMetric(isMetricArg: Boolean): Unit = { - isMetric = isMetricArg - setIncrementAndUnits() - repaint() - } - def setIncrementAndUnits() { - if (isMetric) { - units = (Inch.toDouble / 2.54).toInt - increment = units - } - else { - units = Inch - increment = units / 2 - } - } - def setPreferredHeight(ph: Int): Unit = { - preferredSize = new Dimension(Size, ph) - } - def setPreferredWidth(pw: Int): Unit = { - preferredSize = new Dimension(pw, Size) - } - def paintComponent(g: Graphics): Unit = { - val drawHere: Rectangle = g.getClipBounds() - - // Fill clipping area with dirty brown/orange. - g.setColor(new Color(230, 163, 4)) - g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height) - - // Do the ruler labels in a small font that's black. - g.setFont(new Font("SansSerif", Font.PLAIN, 10)) - g.setColor(Color.black) - - // Some vars we need. - var end = 0 - var start = 0 - var tickLength = 0 - var text: String = null - - // Use clipping bounds to calculate first and last tick locations. - if (orientation == Rule.Horizontal) { - start = (drawHere.x / increment) * increment; - end = (((drawHere.x + drawHere.width) / increment) + 1) * increment - } else { - start = (drawHere.y / increment) * increment; - end = (((drawHere.y + drawHere.height) / increment) + 1) * increment - } - - // Make a special case of 0 to display the number - // within the rule and draw a units label. - if (start == 0) { - val u = if (isMetric) " cm" else " in" - text = Integer.toString(0) + u - tickLength = 10 - if (orientation == Rule.Horizontal) { - g.drawLine(0, Size - 1, 0, Size - tickLength - 1) - g.drawString(text, 2, 21) - } else { - g.drawLine(Size - 1, 0, Size - tickLength - 1, 0) - g.drawString(text, 9, 10) - } - text = null - start = increment - } - - // ticks and labels - for (i <- start until end by increment) { - if (i % units == 0) { - tickLength = 10 - text = Integer.toString(i / units) - } else { - tickLength = 7 - text = null - } - - if (tickLength != 0) { - if (orientation == Rule.Horizontal) { - g.drawLine(i, Size - 1, i, Size - tickLength - 1) - if (text != null) - g.drawString(text, i - 3, 21) - } else { - g.drawLine(Size - 1, i, Size - tickLength - 1, i) - if (text != null) - g.drawString(text, 9, i + 3) - } - } - } - } -} - -object Rule { - val Horizontal = 0 - val Vertical = 1 -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala index f36aa935..12509766 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala @@ -31,21 +31,24 @@ */ package scala.swing.examples.tutorials.components +//import java.awt._ + +import java.awt.{Dimension, Toolkit, Color, Font} + import scala.swing._ -import javax.swing.{ImageIcon, ScrollPaneConstants} -import java.awt.{ Color, Dimension, Font } -import java.net.URL -import scala.swing.event.ButtonClicked +import javax.swing.{SwingConstants, ImageIcon, ScrollPaneConstants} +import scala.swing.Component +import scala.swing.event.{MouseDragged, Key, MouseMoved, ButtonClicked} -/** +/* * Tutorial: How to Use Scroll Panes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html * * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollDemo.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Rule.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Corner.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollablePicture.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollDemo.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Rule.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Corner.java + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollablePicture.java * * ScrollDemo.scala requires these files: * Rule.scala @@ -55,17 +58,19 @@ import scala.swing.event.ButtonClicked */ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { //Get the image to use. - val bee: ImageIcon = ScrollDemo.createImageIcon("/scala/swing/examples/tutorials/images/flyingBee.jpg").get + val beeOp: Option[ImageIcon] = ScrollDemo.createImageIcon("/scala/swing/examples/tutorials/images/scala-stairs.jpg") //Create the row and column headers. - val columnView = new Rule(Rule.Horizontal, true); - val rowView = new Rule(Rule.Vertical, true); - if (bee != null) { - columnView.setPreferredWidth(bee.getIconWidth()) - rowView.setPreferredHeight(bee.getIconHeight()) - } else { - columnView.setPreferredWidth(320) - rowView.setPreferredHeight(480) + val columnView = new Rule(Rule.Horizontal, true) + val rowView = new Rule(Rule.Vertical, true) + + beeOp match { + case Some( bee ) => + columnView.preferredWidth = bee.getIconWidth + rowView.preferredHeight = bee.getIconHeight + case None => + columnView.preferredWidth = 320 + rowView.preferredWidth = 480 } //Create the corners. @@ -79,27 +84,27 @@ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { } //Set up the scroll pane. - val picture = new ScrollablePicture(bee, columnView.increment) + val picture = new ScrollablePicture(beeOp, columnView.increment) val pictureScrollPane = new ScrollPane(picture) { preferredSize = new Dimension(300, 250) columnHeaderView = columnView rowHeaderView = rowView } pictureScrollPane.peer.setViewportBorder(Swing.LineBorder(Color.black)) - + //Set the corners. - //In theory, to support internationalization you would change - //UPPER_LEFT_CORNER to UPPER_LEADING_CORNER, - //LOWER_LEFT_CORNER to LOWER_LEADING_CORNER, and - //UPPER_RIGHT_CORNER to UPPER_TRAILING_CORNER. In practice, - //bug #4467063 makes that impossible (in 1.4, at least). + //In theory, to support internationalization you would change + //UPPER_LEFT_CORNER to UPPER_LEADING_CORNER, + //LOWER_LEFT_CORNER to LOWER_LEADING_CORNER, and + //UPPER_RIGHT_CORNER to UPPER_TRAILING_CORNER. In practice, + //bug #4467063 makes that impossible (in 1.4, at least). pictureScrollPane.peer.setCorner(ScrollPaneConstants.UPPER_LEADING_CORNER, buttonCorner.peer) pictureScrollPane.peer.setCorner(ScrollPaneConstants.LOWER_LEADING_CORNER, new Corner()) pictureScrollPane.peer.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, new Corner()) - + contents += pictureScrollPane border = Swing.EmptyBorder(20, 20, 20, 20) - + listenTo(isMetric) // Original had an itemListener. Scala Swing makes no provision // for item changed events, so use button clicked instead. @@ -113,18 +118,182 @@ class ScrollDemo extends BoxPanel(Orientation.Horizontal) { rowView.setIsMetric(false) columnView.setIsMetric(false) } - picture.setMaxUnitIncrement(rowView.increment) + picture.setMaxUnitIncrement(rowView.increment) } } object ScrollDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { + def createImageIcon(path: String ): Option[javax.swing.ImageIcon] = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } lazy val top = new MainFrame() { title = "ScrollDemo" contents = new ScrollDemo() } +} + + + + + +class ScrollablePicture(img: Option[ImageIcon], var maxUnitIncrement: Int) extends ScrollPane( new Label("", img.orNull, Alignment.Center)) { + + private var missingPicture = false + + if( img == None) { + missingPicture = true +// text = "No picture found." +// horizontalAlignment = Alignment.Center + opaque = true + background = Color.white + } + + //Let the user scroll by dragging to outside the window. + peer.setAutoscrolls(true) + listenTo(mouse.moves) + reactions += { + case MouseMoved(source: Component, point: Point, modifiers: Key.Modifiers) => + peer.scrollRectToVisible(new Rectangle(point.x, point.y)) + case MouseDragged(source: Component, point: Point, modifiers: Key.Modifiers) => + peer.scrollRectToVisible(new Rectangle(point.x, point.y)) + } + + def getPreferredScrollableViewportSize: Dimension = + if (missingPicture) new Dimension(320, 480) + else preferredSize + + + def getScrollableUnitIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { + //Get the current position. + val currentPosition = + if (orientation == SwingConstants.HORIZONTAL) visibleRect.x + else visibleRect.y + + + //Return the number of pixels between currentPosition + //and the nearest tick mark in the indicated direction. + if (direction < 0) { + val newPosition = currentPosition - (currentPosition / maxUnitIncrement) * maxUnitIncrement + if (newPosition == 0) maxUnitIncrement else newPosition + } else { + ((currentPosition / maxUnitIncrement) + 1) * maxUnitIncrement -currentPosition + } + } + + def getScrollableBlockIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { + if (orientation == SwingConstants.HORIZONTAL) + visibleRect.width - maxUnitIncrement + else + visibleRect.height - maxUnitIncrement + } + + def scrollableTracksViewportWidth: Boolean = false + + def scrollableTracksViewportHeight: Boolean = false + + def setMaxUnitIncrement(pixels: Int): Unit = { + maxUnitIncrement = pixels + } +} + + + +class Rule(val orientation: Int, var isMetric: Boolean) extends Component { + val Inch: Int = Toolkit.getDefaultToolkit.getScreenResolution + val Size = 35 + + def units = + if (isMetric) (Inch.toDouble / 2.54).toInt // dots per centimeter + else Inch + + def increment = if (isMetric) units else units / 2 + + def setIsMetric(isMetricArg: Boolean): Unit = { + isMetric = isMetricArg + repaint() + } + + + // def setPreferredHeight(ph: Int): Unit = { + // preferredSize = new Dimension(Size, ph) + // } + // def setPreferredWidth(pw: Int): Unit = { + // preferredSize = new Dimension(pw, Size) + // } + + + def preferredHeight = preferredSize.height + def preferredHeight_=(ph: Int): Unit = preferredSize = new Dimension(Size, ph) + + def preferredWidth = preferredSize.width + def preferredWidth_=(pw: Int): Unit = preferredSize = new Dimension(pw, Size) + + + override def paintComponent(g: Graphics2D): Unit = { + val drawHere: Rectangle = g.getClipBounds + + // Fill clipping area with dirty brown/orange. + g.setColor(new Color(230, 163, 4)) + g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height) + + // Do the ruler labels in a small font that's black. + g.setFont(new Font("SansSerif", Font.PLAIN, 10)) + g.setColor(Color.black) + + // Some vars we need. + var tickLength = 0 + var text: String = null + + // Use clipping bounds to calculate first and last tick locations. + var (start, end) = + if (orientation == Rule.Horizontal) + ( (drawHere.x / increment) * increment, (((drawHere.x + drawHere.width) / increment) + 1) * increment ) + else + ( (drawHere.y / increment) * increment, (((drawHere.y + drawHere.height) / increment) + 1) * increment ) + + // Make a special case of 0 to display the number + // within the rule and draw a units label. + if (start == 0) { + val u = if (isMetric) " cm" else " in" + text = Integer.toString(0) + u + tickLength = 10 + + if (orientation == Rule.Horizontal) { + drawText(0, Some(text), (0, Size - 1), (0, Size - tickLength - 1), (2, 21)) + } else { + drawText(0, Some(text), (Size - 1, 0), (Size - tickLength - 1, 0), (9, 10)) + } + text = null + start = increment + } + + // ticks and labels + for (i <- start until end by increment) { + + val(tickLength, text ) = + if(i % units == 0 ) (10, Some(Integer.toString(i / units) )) + else (7, None) + + + if (tickLength != 0) { + if (orientation == Rule.Horizontal) drawText(i, text, (i, Size - 1), (i, Size - tickLength - 1), (i - 3, 21)) + else drawText(i, text, (Size - 1, i), (Size - tickLength - 1, i), (9, i + 3)) + } + } + + + def drawText(i:Int, text:Option[String], lineFrom:(Int, Int), lineTo:(Int, Int), txtLoc:(Int, Int) ): Unit = { + g.drawLine(lineFrom._1, lineFrom._2, lineTo._1, lineTo._2) + text.foreach( txt => g.drawString(txt, txtLoc._1, txtLoc._2)) + + } + + + } + +} + +object Rule { + val Horizontal = 0 + val Vertical = 1 } \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala index 1362ef13..e01f4f0c 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala @@ -36,12 +36,12 @@ import scala.swing.event.MouseReleased import javax.swing.SwingUtilities import java.awt.{Color, Dimension, Graphics2D, Rectangle} -/** +/* * Tutorial: How to Use Scroll Panes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html]] + * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html * * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemo2Project/src/components/ScrollDemo2.java]] + * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemo2Project/src/components/ScrollDemo2.java * * ScrollDemo2.scala requires no other files. */ diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala deleted file mode 100644 index 39a54625..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollablePicture.scala +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.{ Key, MouseDragged, MouseMoved } -import javax.swing.{ ImageIcon, Scrollable, SwingConstants } -import java.awt.{ Color, Dimension, Rectangle } -import scala.swing.event.MouseMoved - -class ScrollablePicture(i: ImageIcon, var maxUnitIncrement: Int) - extends Label("", i, Alignment.Center) with Scrollable { - private var missingPicture = false - if (i == null) { - missingPicture = true - text = "No picture found." - horizontalAlignment = Alignment.Center - opaque = true - background = Color.white - } - - //Let the user scroll by dragging to outside the window. - peer.setAutoscrolls(true) - listenTo(mouse.moves) - reactions += { - case MouseMoved(source: Component, point: Point, modifiers: Key.Modifiers) => - peer.scrollRectToVisible(new Rectangle(point.x, point.y)) - case MouseDragged(source: Component, point: Point, modifiers: Key.Modifiers) => - peer.scrollRectToVisible(new Rectangle(point.x, point.y)) - } - - def getPreferredScrollableViewportSize(): Dimension = { - if (missingPicture) { - new Dimension(320, 480) - } else { - preferredSize - } - } - - def getScrollableUnitIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { - //Get the current position. - val currentPosition = if (orientation == SwingConstants.HORIZONTAL) { - visibleRect.x; - } else { - visibleRect.y; - } - - //Return the number of pixels between currentPosition - //and the nearest tick mark in the indicated direction. - if (direction < 0) { - val newPosition = currentPosition - - (currentPosition / maxUnitIncrement) * maxUnitIncrement - if (newPosition == 0) maxUnitIncrement else newPosition - } else { - ((currentPosition / maxUnitIncrement) + 1) * maxUnitIncrement - -currentPosition - } - } - - def getScrollableBlockIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { - if (orientation == SwingConstants.HORIZONTAL) - visibleRect.width - maxUnitIncrement - else - visibleRect.height - maxUnitIncrement - } - - def getScrollableTracksViewportWidth(): Boolean = { - false - } - - def getScrollableTracksViewportHeight(): Boolean = { - false - } - - def setMaxUnitIncrement(pixels: Int): Unit = { - maxUnitIncrement = pixels - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala index af5d0827..df039ae2 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala @@ -32,7 +32,6 @@ package scala.swing.examples.tutorials.components import scala.swing._ import scala.swing.event.MouseClicked -import scala.swing.event.MouseClicked /* * Tutorial: How to Use Tables * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] @@ -50,11 +49,11 @@ class SimpleTableDemo extends GridPanel(1, 0) { "# of Years", "Vegetarian") val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) - data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) - data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) - data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) - data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + data(0) = Array("Kathy", "Smith", "Snowboarding", 5, false) + data(1) = Array("John", "Doe", "Rowing", 3, true) + data(2) = Array("Sue", "Black", "Knitting", 2, false) + data(3) = Array("Jane", "White", "Speed reading", 20, true) + data(4) = Array("Joe", "Brown", "Pool", 10, false) val table = new Table(data, columnNames) { preferredViewportSize = new Dimension(500, 70) @@ -75,7 +74,7 @@ class SimpleTableDemo extends GridPanel(1, 0) { private def printDebugData(table: Table): Unit = { val numRows = table.rowCount - val numCols = table.peer.getColumnCount() + val numCols = table.peer.getColumnCount val model: javax.swing.table.TableModel = table.model println("Value of data: ") diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala index 892a1d1b..c4be6abc 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala @@ -48,17 +48,19 @@ class SimpleTableSelectionDemo extends GridPanel(1, 0) { private val Debug = true private val AllowColumnSelection = false private val AllowRowSelection = true + val columnNames: Array[String] = Array("First Name", "Last Name", "Sport", "# of Years", "Vegetarian") + val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) - data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) - data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) - data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) - data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) + data(0) = Array("Kathy", "Smith", "Snowboarding", 5, false) + data(1) = Array("John", "Doe", "Rowing", 3, true) + data(2) = Array("Sue", "Black", "Knitting", 2, false) + data(3) = Array("Jane", "White", "Speed reading", 20, true) + data(4) = Array("Joe", "Brown", "Pool", 10, false) val table = new Table(data, columnNames) { preferredViewportSize = new Dimension(500, 70) @@ -89,14 +91,12 @@ class SimpleTableSelectionDemo extends GridPanel(1, 0) { } if (AllowColumnSelection) { // false by default - if (AllowRowSelection || - table.selection.elementMode == Table.ElementMode.Row) { + if (AllowRowSelection || table.selection.elementMode == Table.ElementMode.Row) { //We allow both row and column selection, which //implies that we *really* want to allow individual //cell selection. table.selection.elementMode = Table.ElementMode.Cell - } - else if (table.selection.elementMode == Table.ElementMode.None) { + } else if (table.selection.elementMode == Table.ElementMode.None) { table.selection.elementMode = Table.ElementMode.Column } listenTo(table.selection) @@ -104,12 +104,8 @@ class SimpleTableSelectionDemo extends GridPanel(1, 0) { case TableColumnsSelected(`table`, range: Range, adjusting: Boolean) => //Ignore extra messages. if (!adjusting) { - if (range.isEmpty) { - println("No rows are selected.") - } else { - val selectedColumn = range.head - println("Column " + selectedColumn + " is now selected.") - } + if (range.isEmpty) println("No rows are selected.") + else println(s"Column ${range.head} is now selected.") } } } @@ -128,7 +124,7 @@ class SimpleTableSelectionDemo extends GridPanel(1, 0) { private def printDebugData(table: Table): Unit = { val numRows = table.rowCount - val numCols = table.peer.getColumnCount() + val numCols = table.peer.getColumnCount val model: javax.swing.table.TableModel = table.model println("Value of data: ") diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala index 60d3fad2..9f7847df 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo.scala @@ -36,7 +36,6 @@ import scala.swing.event.{ ValueChanged, WindowDeiconified, WindowIconified } import java.awt.Font import java.awt.event.{ ActionEvent, ActionListener } import javax.swing.Timer -import java.net.URL import javax.swing.{ImageIcon, UIManager} /** @@ -51,12 +50,12 @@ import javax.swing.{ImageIcon, UIManager} */ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with ActionListener { //Set up animation parameters. - val FpsMin = 0; - val FpsMax = 30; - val FpsInit = 15; //initial frames per second + val FpsMin = 0 + val FpsMax = 30 + val FpsInit = 15 //initial frames per second var frameNumber = 0 val NumFrames = 14 - val images = new Array[ImageIcon](NumFrames) + val images = new Array[Option[ImageIcon]](NumFrames) var frozen = false var delay = 1000 / FpsInit @@ -94,10 +93,10 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act border = Swing.EmptyBorder(10, 10, 10, 10) //Set up a timer that calls this object's action handler. - val timer = new Timer(delay, this); - timer.setInitialDelay(delay * 7); //We pause animation twice per cycle + val timer = new Timer(delay, this) + timer.setInitialDelay(delay * 7) //We pause animation twice per cycle //by restarting the timer - timer.setCoalesce(true); + timer.setCoalesce(true) listenTo(framesPerSecond) listenTo(window) @@ -106,7 +105,7 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act if (!framesPerSecond.adjusting) { val fps: Int = framesPerSecond.value if (fps == 0) { - if (!frozen) stopAnimation(); + if (!frozen) stopAnimation() } else { delay = 1000 / fps timer.setDelay(delay) @@ -124,29 +123,24 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act def startAnimation(): Unit = { //Start (or restart) animating! - timer.start(); - frozen = false; + timer.start() + frozen = false } def stopAnimation(): Unit = { //Stop the animating thread. - timer.stop(); - frozen = true; + timer.stop() + frozen = true } //Called when the Timer fires. def actionPerformed(e: ActionEvent): Unit = { //Advance the animation frame. - if (frameNumber == (NumFrames - 1)) { - frameNumber = 0 - } else { - frameNumber += 1 - } + frameNumber = if (frameNumber == (NumFrames - 1)) 0 else frameNumber + 1 updatePicture(frameNumber); //display the next picture - if (frameNumber == (NumFrames - 1) - || frameNumber == (NumFrames / 2 - 1)) { + if (frameNumber == (NumFrames - 1) || frameNumber == (NumFrames / 2 - 1)) { timer.restart() } } @@ -155,16 +149,13 @@ class SliderDemo(window: Window) extends BoxPanel(Orientation.Vertical) with Act def updatePicture(frameNum: Int): Unit = { //Get the image if we haven't already. if (images(frameNumber) == null) { - images(frameNumber) = SliderDemo.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" + - frameNumber + - ".gif").get; + images(frameNumber) = SliderDemo.createImageIcon(s"/scala/swing/examples/tutorials/images/doggy/T$frameNumber.gif") } //Set the image. - if (images(frameNumber) != null) { - picture.icon = images(frameNumber) - } else { //image not found - picture.text = "image #" + frameNumber + " not found" + images(frameNumber) match { + case Some( frm ) => picture.icon = frm + case None => picture.text = s"image #$frameNumber not found" } } } @@ -179,7 +170,7 @@ object SliderDemo extends SimpleSwingApplication { lazy val top = new MainFrame() { title = "SliderDemo" //Create and set up the content pane. - contents = new SliderDemo(this); + contents = new SliderDemo(this) } } diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala deleted file mode 100644 index d3513173..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SliderDemo2.scala +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.{ ValueChanged, WindowDeiconified, WindowIconified } -import java.awt.event.{ ActionEvent, ActionListener } -import javax.swing.Timer -import java.net.URL -import javax.swing.ImageIcon -import scala.collection.mutable.HashMap - -/** - * Tutorial: How to Use Sliders - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SliderDemo2Project/src/components/SliderDemo2.java]] - * - * SliderDemo2.scala requires all the files in the /scala/swing/examples/tutorials/images/doggy - * directory. - */ -class SliderDemo2(window: Window) extends BorderPanel with ActionListener { - //Set up animation parameters. - val FpsMin = 0; - val FpsMax = 30; - val FpsInit = 15; //initial frames per second - var frameNumber = 0 - val NumFrames = 14 - val images = new Array[Option[ImageIcon]](NumFrames) - var frozen = false - var delay = 1000 / FpsInit - - //Create the label table. - val labelTable = new HashMap[Int, Label]() - labelTable += 0 -> new Label("Stop") - val slow = FpsMax/10 - labelTable += slow -> new Label("Slow") - labelTable += FpsMax -> new Label("Fast") - - val framesPerSecond = new Slider { - orientation = Orientation.Vertical - min = FpsMin - max = FpsMax - value = FpsInit - //Turn on labels at major tick marks. - majorTickSpacing = 10 - paintLabels = true - paintTicks = true - labels = labelTable - } - - val picture = new Label() { - horizontalAlignment = Alignment.Center - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - Swing.Lowered - border = Swing.CompoundBorder( - Swing.BeveledBorder(Swing.Lowered), Swing.EmptyBorder(10, 10, 10, 10)) - } - - updatePicture(0); //display first frame - layout(framesPerSecond) = BorderPanel.Position.West - layout(picture) = BorderPanel.Position.Center - border = Swing.EmptyBorder(10, 10, 10, 10) - - //Set up a timer that calls this object's action handler. - val timer = new Timer(delay, this); - timer.setInitialDelay(delay * 7); //We pause animation twice per cycle - //by restarting the timer - timer.setCoalesce(true); - - listenTo(framesPerSecond) - listenTo(window) - reactions += { - case ValueChanged(`framesPerSecond`) => - if (!framesPerSecond.adjusting) { - val fps: Int = framesPerSecond.value - if (fps == 0) { - if (!frozen) stopAnimation(); - } else { - delay = 1000 / fps - timer.setDelay(delay) - timer.setInitialDelay(delay * 10) - if (frozen) startAnimation() - } - } - case WindowIconified(`window`) => - stopAnimation() - case WindowDeiconified(`window`) => - startAnimation() - } - - startAnimation() - - def startAnimation(): Unit = { - //Start (or restart) animating! - timer.start(); - frozen = false; - } - - def stopAnimation(): Unit = { - //Stop the animating thread. - timer.stop(); - frozen = true; - } - - //Called when the Timer fires. - def actionPerformed(e: ActionEvent): Unit = { - //Advance the animation frame. - if (frameNumber == (NumFrames - 1)) { - frameNumber = 0 - } else { - frameNumber += 1 - } - - updatePicture(frameNumber); //display the next picture - - if (frameNumber == (NumFrames - 1) - || frameNumber == (NumFrames / 2 - 1)) { - timer.restart() - } - } - - /** Update the label to display the image for the current frame. */ - def updatePicture(frameNum: Int): Unit = { - //Get the image if we haven't already. - if (images(frameNumber) == null) { - images(frameNumber) = SliderDemo2.createImageIcon("/scala/swing/examples/tutorials/images/doggy/T" - + frameNumber - + ".gif") - } - - //Set the image. - if (images(frameNumber).isDefined) { - picture.icon = images(frameNumber).get - } else { //image not found - picture.text = "image #" + frameNumber + " not found" - } - } -} - -object SliderDemo2 extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } - - lazy val top = new MainFrame() { - title = "SliderDemo2" - javax.swing.UIManager.put("swing.boldMetal", false) - //Create and set up the content pane. - contents = new SliderDemo2(this); - } - - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) -} - diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala index f579d055..3efd6018 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo.scala @@ -1,107 +1,107 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.SelectionChanged -import java.awt.Font -import java.net.URL -import javax.swing.ImageIcon - -//SplitPaneDemo itself is not a visible component. It is used by SplitPaneDemo2.scala. -class SplitPaneDemo extends FlowPanel { - val imageNames: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig", - "dukeWaveRed", "kathyCosmo", "left", "middle", "right", "stickerface") - //Create the list of images and put it in a scroll pane. - val list = new ListView[String](imageNames) - list.selection.intervalMode = ListView.IntervalMode.Single - list.selectIndices(0) - // - val listScrollPane = new ScrollPane(list) - val picture = new Label() { - horizontalAlignment = Alignment.Center - } - picture.font = font.deriveFont(Font.ITALIC) - val pictureScrollPane = new ScrollPane(picture) - - //Create a split pane with the two scroll panes in it. - //Use Orientation.Vertical to get a left/right split pane - val splitPane = new SplitPane(Orientation.Vertical, listScrollPane, pictureScrollPane) { - oneTouchExpandable = true - dividerLocation = 150 - } - - // Provide minimum sizes for the two components in the split pane. - listScrollPane.minimumSize = new Dimension(100, 50) - pictureScrollPane.minimumSize = new Dimension(400, 200) - updateLabel(imageNames(list.selection.leadIndex)) - listenTo(list.selection) - - reactions += { - case SelectionChanged(`list`) => - updateLabel(imageNames(list.selection.leadIndex)) - } - - //Renders the selected image - def updateLabel (name: String): Unit = { - val icon: Option[ImageIcon] = SplitPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + name + ".gif") - if (icon.isDefined) { - picture.text = null - picture.icon = icon.get - } else { - picture.text = "Image not found" - picture.icon = null - } - } - - //Used by SplitPaneDemo2 - def getImageList(): ListView[String] = { - list; - } - - def getSplitPane(): SplitPane = { - splitPane; - } -} - -object SplitPaneDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or NOne if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } - - lazy val top = new MainFrame() { - title = "SplitPaneDemo" - contents = new SplitPaneDemo() - } -} - +///* +// * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. +// * +// * Redistribution and use in source and binary forms, with or without +// * modification, are permitted provided that the following conditions +// * are met: +// * +// * - Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * +// * - Redistributions in binary form must reproduce the above copyright +// * notice, this list of conditions and the following disclaimer in the +// * documentation and/or other materials provided with the distribution. +// * +// * - Neither the name of Oracle or the names of its +// * contributors may be used to endorse or promote products derived +// * from this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ +// +//package scala.swing.examples.tutorials.components +// +//import scala.swing._ +//import scala.swing.event.SelectionChanged +//import java.awt.Font +//import java.net.URL +//import javax.swing.ImageIcon +// +////SplitPaneDemo itself is not a visible component. It is used by SplitPaneDemo2.scala. +//class SplitPaneDemo extends FlowPanel { +// val imageNames: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig", +// "dukeWaveRed", "kathyCosmo", "left", "middle", "right", "stickerface") +// //Create the list of images and put it in a scroll pane. +// val list = new ListView[String](imageNames) +// list.selection.intervalMode = ListView.IntervalMode.Single +// list.selectIndices(0) +// // +// val listScrollPane = new ScrollPane(list) +// val picture = new Label() { +// horizontalAlignment = Alignment.Center +// } +// picture.font = font.deriveFont(Font.ITALIC) +// val pictureScrollPane = new ScrollPane(picture) +// +// //Create a split pane with the two scroll panes in it. +// //Use Orientation.Vertical to get a left/right split pane +// val splitPane = new SplitPane(Orientation.Vertical, listScrollPane, pictureScrollPane) { +// oneTouchExpandable = true +// dividerLocation = 150 +// } +// +// // Provide minimum sizes for the two components in the split pane. +// listScrollPane.minimumSize = new Dimension(100, 50) +// pictureScrollPane.minimumSize = new Dimension(400, 200) +// updateLabel(imageNames(list.selection.leadIndex)) +// listenTo(list.selection) +// +// reactions += { +// case SelectionChanged(`list`) => +// updateLabel(imageNames(list.selection.leadIndex)) +// } +// +// //Renders the selected image +// def updateLabel (name: String): Unit = { +// val icon: Option[ImageIcon] = SplitPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/" + name + ".gif") +// if (icon.isDefined) { +// picture.text = null +// picture.icon = icon.get +// } else { +// picture.text = "Image not found" +// picture.icon = null +// } +// } +// +// //Used by SplitPaneDemo2 +// def getImageList(): ListView[String] = { +// list; +// } +// +// def getSplitPane(): SplitPane = { +// splitPane; +// } +//} +// +//object SplitPaneDemo extends SimpleSwingApplication { +// /** Returns an ImageIcon option, or NOne if the path was invalid. */ +// def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { +// Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) +// } +// +// lazy val top = new MainFrame() { +// title = "SplitPaneDemo" +// contents = new SplitPaneDemo() +// } +//} +// diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala index 87486b56..b83cfb62 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDemo2.scala @@ -31,9 +31,10 @@ package scala.swing.examples.tutorials.components +import java.awt.Font + import scala.swing._ import scala.swing.event.SelectionChanged -import java.net.URL import javax.swing.ImageIcon /** @@ -52,8 +53,8 @@ class SplitPaneDemo2 extends MainFrame { //Create an instance of SplitPaneDemo. val splitPaneDemo = new SplitPaneDemo() - val top: SplitPane = splitPaneDemo.getSplitPane() - val listMe: ListView[String] = splitPaneDemo.getImageList() + val top: SplitPane = splitPaneDemo.splitPane + val listMe: ListView[String] = splitPaneDemo.imageList //XXXX: Bug #4131528, borders on nested split panes accumulate. //Workaround: Set the border on any split pane within @@ -81,23 +82,78 @@ class SplitPaneDemo2 extends MainFrame { //Add the split pane to this frame contents = splitPane - listenTo(splitPaneDemo.getImageList().selection) + listenTo(splitPaneDemo.imageList.selection) reactions += { case (e: SelectionChanged) => - val theList: ListView[String] = e.source.asInstanceOf[ListView[String]] - if (!theList.selection.adjusting) { - if (theList.selection.leadIndex < 0) - label.text = "Nothing selected." - } else { - val index = theList.selection.leadIndex - label.text = "Selected image number " + index - } + val theList: ListView[String] = e.source.asInstanceOf[ListView[String]] + if (!theList.selection.adjusting) { + if (theList.selection.leadIndex < 0) + label.text = "Nothing selected." + } else { + val index = theList.selection.leadIndex + label.text = s"Selected image number $index" + } } } object SplitPaneDemo2 extends SimpleSwingApplication { + def createImageIcon(path: String): Option[javax.swing.ImageIcon] = + Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) + lazy val top = new SplitPaneDemo2() } + + +class SplitPaneDemo extends FlowPanel { + val imageNames: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig", + "dukeWaveRed", "kathyCosmo", "left", "middle", "right", "stickerface") + + //Create the list of images and put it in a scroll pane. + val imageList = new ListView[String](imageNames) + imageList.selection.intervalMode = ListView.IntervalMode.Single + imageList.selectIndices(0) + + val listScrollPane = new ScrollPane(imageList) { + minimumSize = new Dimension(100, 50) + } + + val picture = new Label() { + horizontalAlignment = Alignment.Center + } + picture.font = font.deriveFont(Font.ITALIC) + val pictureScrollPane = new ScrollPane(picture) { + minimumSize = new Dimension(400, 200) + } + + //Create a split pane with the two scroll panes in it. + //Use Orientation.Vertical to get a left/right split pane + val splitPane = new SplitPane(Orientation.Vertical, listScrollPane, pictureScrollPane) { + oneTouchExpandable = true + dividerLocation = 150 + } + + updateLabel(imageNames(imageList.selection.leadIndex)) + + listenTo(imageList.selection) + + reactions += { + case SelectionChanged(`imageList`) => + updateLabel(imageNames(imageList.selection.leadIndex)) + } + + //Renders the selected image + def updateLabel (name: String): Unit = { + val icon: Option[ImageIcon] = SplitPaneDemo2.createImageIcon("/scala/swing/examples/tutorials/images/" + name + ".gif") + if (icon.isDefined) { + picture.text = null + picture.icon = icon.get + } else { + picture.text = "Image not found" + picture.icon = null + } + } + +} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala index 6ac4ac6b..03ce3b83 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala @@ -34,8 +34,6 @@ package scala.swing.examples.tutorials.components import scala.swing._ import scala.swing.event.ButtonClicked import java.awt.Font -import java.net.URL -import javax.swing.ImageIcon /** * How to Use Split Panes @@ -52,14 +50,14 @@ import javax.swing.ImageIcon */ class SplitPaneDividerDemo extends BorderPanel { font = new Font("Serif", Font.ITALIC, 24) - val icon1 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Cat.gif").get - val sd1 = new SizeDisplayer("left", icon1) { + val icon1 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Cat.gif") + val sd1 = new SizeDisplayer("left", icon1.orNull) { font = font } sd1.setMinimumSize(new Dimension(30,30)) - val icon2 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Dog.gif").get - val sd2 = new SizeDisplayer("right", icon2) { + val icon2 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Dog.gif") + val sd2 = new SizeDisplayer("right", icon2.orNull) { font = font } sd2.setMinimumSize(new Dimension(30,30)) @@ -82,7 +80,7 @@ class SplitPaneDividerDemo extends BorderPanel { reactions += { case ButtonClicked(`reset`) => splitPane.resetToPreferredSizes() } - return panel + panel } } From 722a2a3104b3af6f3601191002b201967c92c174 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Mon, 6 Oct 2014 09:26:40 -0700 Subject: [PATCH 34/36] Fix up borders, x-alignments, and RigidBoxes that were in the original. One bug fix in the handler for the Set button that showed up when the button is clicked without choosing a name in the list. --- .../tutorials/components/ListDialog.scala | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala index 90a0b7ab..8f907f64 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala @@ -106,10 +106,10 @@ class ListDialog(frame: Frame, locationComp: Component, } val buttonPane = new BoxPanel(Orientation.Horizontal) { - border = Swing.EmptyBorder(0, 10, 10, 10) + border = Swing.EmptyBorder(10, 10, 10, 10) contents += Swing.HGlue contents += cancelButton - contents += Swing.HGlue + contents += Swing.RigidBox(new Dimension(10, 0)) contents += setButton } @@ -127,7 +127,7 @@ class ListDialog(frame: Frame, locationComp: Component, listenTo(list.mouse.clicks) reactions += { case ButtonClicked(`setButton`) => - setValue(list.listData(list.selection.leadIndex)) + if (list.selection.leadIndex >= 0) setValue(list.listData(list.selection.leadIndex)) visible = false case ButtonClicked(`cancelButton`) => setValue(initialValue) @@ -177,17 +177,20 @@ class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) "Otto", "Ringo", "Rocco", "Rollo") //Create the labels. - val intro = new Label("The chosen name:") + val intro = new Label("The chosen name:") { + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT + } val nameLabel = new Label(names(1)) { //Use a wacky font if it exists. If not, this falls //back to a font we know exists. font = getAFont + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } intro.peer.setLabelFor(nameLabel.peer) //Create the button. val button = new Button("Pick a new name...") { - + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT } listenTo(button) @@ -205,9 +208,13 @@ class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) } - + border = Swing.EmptyBorder(20, 20, 10, 20) + //Add the labels to the content pane. contents += intro + contents += Swing.VStrut(5) contents += nameLabel + //Add a vertical spacer that also guarantees us a minimum width: + contents += Swing.RigidBox(new Dimension(150, 10)) contents += button From db8615a55ce9ab4f413dc97c4505ec7826b0a331 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Mon, 6 Oct 2014 11:13:15 -0700 Subject: [PATCH 35/36] Undecorated window case enabled in FrameDemo2. Removed all uses of peer comoponents. --- .../tutorials/components/FrameDemo2.scala | 110 ++++++++++-------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala index 0b5ec75f..1ed40e19 100644 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala @@ -77,21 +77,11 @@ class FrameDemo2 { //Create a new MyFrame object and show it. def showNewWindow(): Unit = { - val frame: Option[Frame] = if (noDecorations) None else Some(new MyFrame()) - //Take care of the no window decorations case. //NOTE: Unless you really need the functionality //provided by JFrame, you would usually use a //Window or JWindow instead of an undecorated JFrame. - - //Undecorated frames are not supported by scala swing. Setting the Frame's - //JFrame peer to be undecorated causes Swing to throw a java.awt.IllegalComponentStateException - //with the message "The frame is displayable." - // - //if (noDecorations) { - // frame.peer.setUndecorated(true); - //} - + val frame: Option[Frame] = if (noDecorations) Some(new MyFrameUndecorated()) else Some(new MyFrame()) //Set window location. if (frame.isDefined) { val f = frame.get @@ -123,7 +113,7 @@ class FrameDemo2 { } // Create the window-creation controls that go in the main window. - def createOptionControls(frame: Frame): Box = { + def createOptionControls(frame: Frame): BoxPanel = { val label1 = new Label("Decoration options for subsequently created frames:") val bg1 = new ButtonGroup() val label2 = new Label("Icon options:") @@ -163,22 +153,20 @@ class FrameDemo2 { bg2.buttons += rb6 //Add everything to a container. - val box = Box.createVerticalBox() - box.add(label1.peer) - box.add(Swing.VStrut(5).peer) // spacer - box.add(rb1.peer) - box.add(rb2.peer) - box.add(rb3.peer) - // - box.add(Swing.VStrut(15).peer) // spacer - box.add(label2.peer) - box.add(Swing.VStrut(5).peer) // spacer - box.add(rb4.peer) - box.add(rb5.peer) - box.add(rb6.peer) - - //Add some breathing room. - box.setBorder(Swing.EmptyBorder(10, 10, 10, 10)) + val box = new BoxPanel(Orientation.Vertical) { + border = Swing.EmptyBorder(10, 10, 10, 10) + contents += label1 + contents += Swing.VStrut(5) // spacer + contents += rb1 + contents += rb2 + contents += rb3 + contents += Swing.VStrut(15) + contents += label2 + contents += Swing.VStrut(5) + contents += rb4 + contents += rb5 + contents += rb6 + } frame.listenTo(rb1) frame.listenTo(rb2) @@ -195,13 +183,8 @@ class FrameDemo2 { JFrame.setDefaultLookAndFeelDecorated(false) case ButtonClicked(`rb3`) => noDecorations = true - //Undecorated frames are not supported by scala swing. Setting the Frame's - //JFrame peer to be undecorated causes Swing to throw a java.awt.IllegalComponentStateException - //with the message "The frame is displayable." - // // No need to set the default look and feel decorated property to false. // JFrame.setDefaultLookAndFeelDecorated(false) - println("Undecorated frames are not supported by Scala Swing.") case ButtonClicked(`rb4`) => specifyIcon = false case ButtonClicked(`rb5`) => specifyIcon = true @@ -215,7 +198,7 @@ class FrameDemo2 { } //Create the button that goes in the main window. - def createButtonPane(frame: Frame): javax.swing.JComponent = { + def createButtonPane(frame: Frame): FlowPanel = { val button = new Button("New window") defaultButton = button @@ -229,7 +212,7 @@ class FrameDemo2 { border = Swing.EmptyBorder(5, 5, 5, 5) contents += button } - pane.peer + pane } } @@ -238,16 +221,45 @@ class MyFrame extends Frame { title = "A window" //This button lets you close even an undecorated window. - val button = new Button("Close window") + val button = new Button("Close window") { + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT + } + + //Place the button near the bottom of the window. + contents = new BoxPanel(Orientation.Vertical) { + contents += Swing.VGlue + contents += button + contents += Swing.VStrut(5) + } + // + listenTo(button) + reactions += { + case ButtonClicked(`button`) => + visible = false + dispose() + } + preferredSize = new Dimension(150, 150) + pack() + visible = true + override def closeOperation() = { + close + } +} + +class MyFrameUndecorated extends Frame with RichWindow.Undecorated { + visible = false + //This button lets you close even an undecorated window. + val button = new Button("Close window") { + xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT + } //Place the button near the bottom of the window. - //Undecorated windows are not supported in scala swing. Go to the peer. - val contentPane: java.awt.Container = peer.getContentPane() - contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.PAGE_AXIS)) - contentPane.add(Box.createVerticalGlue()) // takes all extra space - contentPane.add(button.peer) - button.xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - contentPane.add(Box.createVerticalStrut(5)) //spacer + //Undecorated windows are not supported in scala swing. + contents = new BoxPanel(Orientation.Vertical) { + contents += Swing.VGlue + contents += button + contents += Swing.VStrut(5) + } // listenTo(button) reactions += { @@ -307,13 +319,11 @@ object FrameDemo2 extends SimpleSwingApplication { JDialog.setDefaultLookAndFeelDecorated(true); //Create and set up the content pane. val demo = new FrameDemo2(); - //Add components to it. - val contentPane = peer.getContentPane() - } - top.contentPane.add(top.demo.createOptionControls(top), - BorderLayout.CENTER) - top.contentPane.add(top.demo.createButtonPane(top), - BorderLayout.PAGE_END) + val bp: BorderPanel = new BorderPanel() { + layout(top.demo.createOptionControls(top)) = BorderPanel.Position.Center + layout(top.demo.createButtonPane(top)) = BorderPanel.Position.South + } + top.contents = bp javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) } From 19fd1b49942bcba97a4c134214fb94536a59de22 Mon Sep 17 00:00:00 2001 From: Allan Jacobs Date: Mon, 6 Oct 2014 18:50:04 -0700 Subject: [PATCH 36/36] Remove half the files for lack of support in scala swing in the java7 branch. --- .../tutorials/components/Corner.scala | 41 -- .../components/CustomComboBoxDemo.scala | 125 ----- .../tutorials/components/DialogDemo.scala | 391 --------------- .../components/FileChooserDemo.scala | 133 ------ .../components/FormattedTextFieldDemo.scala | 171 ------- .../tutorials/components/FrameDemo2.scala | 329 ------------- .../tutorials/components/ListDialog.scala | 259 ---------- .../tutorials/components/MenuDemo.scala | 219 --------- .../tutorials/components/MenuLookDemo.scala | 192 -------- .../tutorials/components/PopupMenuDemo.scala | 266 ----------- .../tutorials/components/ScrollDemo.scala | 299 ------------ .../tutorials/components/ScrollDemo2.scala | 140 ------ .../components/SimpleTableDemo.scala | 97 ---- .../components/SimpleTableSelectionDemo.scala | 147 ------ .../tutorials/components/SizeDisplayer.scala | 150 ------ .../components/SplitPaneDividerDemo.scala | 98 ---- .../tutorials/components/TabbedPaneDemo.scala | 93 ---- .../tutorials/components/TableDemo.scala | 134 ------ .../components/TableFTFEditDemo.scala | 143 ------ .../tutorials/components/TablePrintDemo.scala | 155 ------ .../components/TableSelectionDemo.scala | 247 ---------- .../components/TextComponentDemo.scala | 445 ------------------ .../tutorials/components/TextDemo.scala | 82 ---- .../components/TextSamplerDemo.scala | 296 ------------ .../tutorials/components/TumbleItem.scala | 289 ------------ .../tutorials/events/ListSelectionDemo.scala | 134 ------ .../tutorials/layout/BorderLayoutDemo.scala | 74 --- .../tutorials/layout/CustomLayoutDemo.scala | 66 --- .../tutorials/layout/FlowLayoutDemo.scala | 101 ---- .../tutorials/layout/GridLayoutDemo.scala | 97 ---- .../examples/tutorials/misc/ActionDemo.scala | 197 -------- 31 files changed, 5610 deletions(-) delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala delete mode 100644 examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala deleted file mode 100644 index a81a81af..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/Corner.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import java.awt.{ Color, Graphics } - -class Corner extends java.awt.Component { - def paintComponent(g: Graphics): Unit = { - // Fill me with dirty brown/orange. - g.setColor(new Color(230, 163, 4)) - g.fillRect(0, 0, getWidth().toInt, getHeight().toInt) - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala deleted file mode 100644 index fc5339e4..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/CustomComboBoxDemo.scala +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components - -import scala.swing._ -import javax.swing.ImageIcon -import java.net.URL -import java.awt.{ Dimension, Font } - -/** - * Tutorial: How to Use Combo Boxes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/CustomComboBoxDemoProject/src/components/CustomComboBoxDemo.java]] - * - * CustomComboBoxDemo.scala uses the following files: - * /scala/swing/examples/tutorials/images/Bird.gif - * /scala/swing/examples/tutorials/images/Cat.gif - * /scala/swing/examples/tutorials/images/Dog.gif - * /scala/swing/examples/tutorials/images/Rabbit.gif - * /scala/swing/examples/tutorials/images/Pig.gif - */ -class CustomComboBoxDemo extends BorderPanel { - val petStrings: Array[String] = Array("Bird", "Cat", "Dog", "Rabbit", "Pig") -// val images: Array[Option[ImageIcon]] = new Array[Option[ImageIcon]](petStrings.length) - val intArray: Array[Int] = (0 until petStrings.length ).toArray - /* - * Despite its use of EmptyBorder, this panel makes a fine content - * pane because the empty border just increases the panel's size - * and is "painted" on top of the panel's normal background. In - * other words, the JPanel fills its entire background if it's - * opaque (which it is by default); adding a border doesn't change - * that. - */ - - val images:Array[Option[ImageIcon]] = petStrings.map( pet => { - val oImage = CustomComboBoxDemo.createImageIcon(s"/scala/swing/examples/tutorials/images/$pet.gif") - oImage.map( img => {img.setDescription(pet); img} ) - }) - - //Create the combo box. - val petList = new ComboBox[Int](intArray) { - renderer = new ComboBoxRenderer() - preferredSize = new Dimension(200, 130) - peer.setMaximumRowCount(3) - } - - //Lay out the demo. - layout(petList) = BorderPanel.Position.Center - border = Swing.EmptyBorder(20, 20, 20, 20) - - class ComboBoxRenderer extends ListView.AbstractRenderer[Int, Label](new Label("")) { - var uhOhFont: Option[Font] = None - /* - * This method finds the image and text corresponding - * to the selected value and returns the label, set up - * to display the text and image. - */ - def configure( listMe: ListView[_], isSelected: Boolean, cellHasFocus: Boolean, a: Int, index: Int): Unit = { - //Set the icon and text. If icon was null, say so. - images(a) match { - case Some( icon ) => - component.icon = icon - component.text = petStrings(a) - component.font = listMe.font - case None => setUhOhText( s"${petStrings(a)} (no image available)", listMe.font) - } - } - - //Set the font and text when no image was found. - def setUhOhText(uhOhText: String, normalFont: Font): Unit = { - if (!uhOhFont.isDefined) { //lazily create this font - uhOhFont = Some(normalFont.deriveFont(Font.ITALIC)) - } - component.font = uhOhFont.getOrElse( normalFont ) - component.text = uhOhText - } - } -} - -object CustomComboBoxDemo extends SimpleSwingApplication { - - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - - lazy val top = new MainFrame() { - title = "CustomComboBoxDemo" - - //Create and set up the content pane. - val newContentPane = new CustomComboBoxDemo() - newContentPane.opaque = true - contents = newContentPane - } - -} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala deleted file mode 100644 index 75c6355f..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/DialogDemo.scala +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.ButtonClicked -import scala.swing.TabbedPane.Page -import javax.swing.border.Border -import javax.swing.ImageIcon -import java.awt.{ Dimension, Font } - -/** - * Tutorial: How to Use Dialogs - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/DialogDemoProject/src/components/DialogDemo.java]] - * - * DialogDemo.scala requires these files: - * CustomDialog.scala - * /scala/swing/examples/tutorials/images/middle.gif - */ -class DialogDemo(val frame: Frame) extends BorderPanel { - val oImage = DialogDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif") - val icon: ImageIcon = if (oImage.isDefined) oImage.get else null - val simpleDialogDesc = "Some simple message dialogs" - val iconDesc = "A JOptionPane has its choice of icons" - val moreDialogDesc = "Some more dialogs" - // val customDialog = new CustomDialog(frame, "geisel", this) - - val padding: Border = Swing.EmptyBorder(20, 20, 5, 20) - //Create the components. - val label: Label = new Label("Click the \"Show it!\" button" + - " to bring up the selected dialog.", Swing.EmptyIcon, Alignment.Center) { - border = Swing.EmptyBorder(10, 10, 10, 10) - } - val frequentPanel = createSimpleDialogBox() - frequentPanel.border = padding - val featurePanel = createFeatureDialogBox() - featurePanel.border = padding - val iconPanel = createIconDialogBox() - iconPanel.border = padding - - //Lay them out. - val tabbedPane = new TabbedPane() - tabbedPane.pages += new Page("Simple Modal Dialogs", frequentPanel, simpleDialogDesc) - tabbedPane.pages += new Page("More Dialogs", featurePanel, moreDialogDesc) - tabbedPane.pages += new Page("Dialog Icons", iconPanel, iconDesc) - - layout(tabbedPane) = BorderPanel.Position.Center - layout(label) = BorderPanel.Position.South - - /** Sets the text displayed at the bottom of the frame. */ - def setLabel(newText: String): Unit = { - label.text = newText - } - /** Creates the panel shown by the first tab. */ - private def createSimpleDialogBox(): BorderPanel = { - - val showItButton: Button = new Button("Show it!") - - val defaultMessageCommandButton =new RadioButton("OK (in the L&F's words)") { selected = true } - val yesNoCommandButton = new RadioButton("Yes/No (in the L&F's words)") - val yeahNahCommandButton = new RadioButton("Yes/No (in the programmer's words)") - val yncCommandButton = new RadioButton("Yes/No/Cancel (in the programmer's words)") - - val radioButtons:Array[RadioButton] = Array( - defaultMessageCommandButton, - yesNoCommandButton, - yeahNahCommandButton, - yncCommandButton - ) - - val group: ButtonGroup = new ButtonGroup() { - radioButtons.foreach( buttons += _ ) - } - - listenTo(showItButton) - - reactions += { - - case ButtonClicked(`showItButton`) if group.selected == Some(defaultMessageCommandButton) => - Dialog.showMessage(this, "Eggs aren't supposed to be green.") - - case ButtonClicked(`showItButton`) if group.selected == Some(yesNoCommandButton) => - Dialog.showConfirmation( - this, "Would you like green eggs and ham?", - "An Inane Question", - Dialog.Options.YesNo) match { - case Dialog.Result.Yes => setLabel("Ewww!") - case Dialog.Result.No => setLabel("Me neither!") - case _ => setLabel("Come on -- tell me!") - } - - - - case ButtonClicked(`showItButton`) if group.selected == Some(yeahNahCommandButton) => - Dialog.showOptions(this, - "Would you like green eggs and ham?", - "A Silly Question", - Dialog.Options.YesNo, - Dialog.Message.Question, - Swing.EmptyIcon, - Array("Yes, please", "No way!"), - 0) match { - - case Dialog.Result.Yes => setLabel("You're kidding!") - case Dialog.Result.No => setLabel("I don't like them, either.") - case _ => setLabel("Come on -- 'fess up!") - } - - case ButtonClicked(`showItButton`) if group.selected == Some(yncCommandButton) => - Dialog.showOptions(this, - "Would you like some green eggs to go with that ham?", - "A Silly Question", - Dialog.Options.YesNoCancel, - Dialog.Message.Question, - null, - Array("Yes, please", "No, thanks", "No eggs, no ham!"), - 2) match { - case Dialog.Result.Yes => setLabel("Here you go: green eggs and ham!") - case Dialog.Result.No => setLabel("OK, just the ham, then.") - case Dialog.Result.Cancel => setLabel("Well, I'm certainly not going to eat them!") - case _ => setLabel("Please tell me what you want!") - } - } - createPane(simpleDialogDesc + ":", radioButtons, showItButton) - } - - /** - * Used by createSimpleDialogBox and createFeatureDialogBox - * to create a pane containing a description, a single column - * of radio buttons, and the Show it! button. - */ - private def createPane(description: String, radioButtons: Array[RadioButton], showButton: Button): BorderPanel = { - - val box: BoxPanel = new BoxPanel(Orientation.Vertical) { - contents += new Label(description) - radioButtons.foreach( contents += _ ) - } - - new BorderPanel() { - layout(box) = BorderPanel.Position.North - layout(showButton) = BorderPanel.Position.South - } - } - - /** - * Like createPane, but creates a pane with 2 columns of radio - * buttons. The number of buttons passed in *must* be even. - */ - private def create2ColPane(description: String, - radioButtons: Array[RadioButton], - showButton: Button): BorderPanel = { - val label = new Label(description) - val numPerColumn = radioButtons.length / 2 - val grid = new GridPanel(numPerColumn, 2) - for (i <- 0 until radioButtons.length) { - grid.contents += radioButtons(i) - } - val box = new BoxPanel(Orientation.Vertical) { - contents += label - grid.xLayoutAlignment = 0.0f - contents += grid - } - - new BorderPanel() { - layout(box) = BorderPanel.Position.North - layout(showButton) = BorderPanel.Position.South - } - } - /* - * Creates the panel shown by the 3rd tab. - * These dialogs are implemented using showMessageDialog, but - * you can specify the icon (using similar code) for any other - * kind of dialog, as well. - */ - def createIconDialogBox(): BorderPanel = { - val plainCommandButton = new RadioButton("Plain (no icon)") { selected = true } - val infoCommandButton = new RadioButton("Information icon") - val questionCommandButton = new RadioButton("Question icon") - val errorCommandButton = new RadioButton("Error icon") - val warningCommandButton = new RadioButton("Warning icon") - val customCommandButton = new RadioButton("Custom icon") - - val radioButtons = Array( - plainCommandButton, - infoCommandButton, - questionCommandButton, - errorCommandButton, - warningCommandButton, - customCommandButton - ) - - val group: ButtonGroup = new ButtonGroup() { - radioButtons.foreach( buttons += _ ) - } - val showItButton = new Button("Show it!") - - listenTo(showItButton) - - reactions += { - case ButtonClicked(`showItButton`) if group.selected == Some(plainCommandButton) => - Dialog.showMessage(this, - "Eggs aren't supposed to be green.", - "A plain message", - Dialog.Message.Plain) - - case ButtonClicked(`showItButton`) if group.selected == Some(infoCommandButton) => - Dialog.showMessage(this, - "Eggs aren't supposed to be green.", - "Inane informational dialog", - Dialog.Message.Info) - - case ButtonClicked(`showItButton`) if group.selected == Some(questionCommandButton) => - Dialog.showMessage(this, - "You shouldn't use a message dialog " + - "(like this)\n" + - "for a question, OK?", - "Inane question", - Dialog.Message.Question) - - case ButtonClicked(`showItButton`) if group.selected == Some(errorCommandButton) => - Dialog.showMessage(this, - "Eggs aren't supposed to be green.", - "Inane error", - Dialog.Message.Error) - - case ButtonClicked(`showItButton`) if group.selected == Some(warningCommandButton) => - Dialog.showMessage(this, - "Eggs aren't supposed to be green.", - "Inane warning", - Dialog.Message.Warning) - - case ButtonClicked(`showItButton`) if group.selected == Some(customCommandButton) => - Dialog.showMessage(this, - "Eggs aren't supposed to be green.", - "Inane custom dialog", - Dialog.Message.Info, - icon) - } - - create2ColPane(iconDesc + ":", radioButtons, showItButton) - } - - /** Creates the panel shown by the second tab. */ - private def createFeatureDialogBox(): BorderPanel = { -// val pickOneCommand = "pickone" -// val textEnteredCommand = "textfield" -// val nonAutoCommand = "nonautooption" -// val customOptionCommand = "customoption" -// val nonModalCommand = "nonmodal" - - val pickOneCommandButton = new RadioButton("Pick one of several choices") { selected = true } - - val textEnteredCommandButton = new RadioButton("Enter some text") - val nonAutoCommandButton = new RadioButton("Non-auto-closing dialog") - val customOptionCommandButton = new RadioButton("Input-validating dialog (with custom message area)") - val nonModalCommandButton = new RadioButton("Non-modal dialog") - - val radioButtons = Array( - pickOneCommandButton, - textEnteredCommandButton, - nonAutoCommandButton, - customOptionCommandButton, - nonModalCommandButton - ) - - val group: ButtonGroup = new ButtonGroup() { - radioButtons.foreach( buttons += _ ) - } - - val showItButton = new Button("Show it!") - - listenTo(showItButton) - - reactions += { - case ButtonClicked(`showItButton`) if group.selected == Some(pickOneCommandButton) => - Dialog.showInput[String](this, - "Complete the sentence:\n" + - "\"Green eggs and...\"", - "Customized Dialog", - Dialog.Message.Plain, - icon, - Array("ham", "spam", "yam"), - "ham") match { - case Some(msg) if msg.length > 1 => setLabel(s"Green eggs and...$msg!") - case _ => setLabel("Come on, finish the sentence!") - } - - case ButtonClicked(`showItButton`) if group.selected == Some(textEnteredCommandButton) => - Dialog.showInput[String](this, - "Complete the sentence:\n" + - "\"Green eggs and...\"", - "Customized Dialog", - Dialog.Message.Plain, - icon, - Nil, - "ham") match { - case Some(msg) if msg.length > 1 => setLabel(s"Green eggs and...$msg!") - case _ => setLabel("Come on, finish the sentence!") - } - - case ButtonClicked(`showItButton`) if group.selected == Some(nonAutoCommandButton) => - setLabel("Not supported.") - //non-auto-closing dialog with custom message area - //NOTE: if you don't intend to check the input, - //then just use showInputDialog instead. - - case ButtonClicked(`showItButton`) if group.selected == Some(customOptionCommandButton) => - setLabel("Not supported.") - - case ButtonClicked(`showItButton`) if group.selected == Some(nonModalCommandButton) => - val dialog = new Dialog(frame, frame.peer.getGraphicsConfiguration) { - title = "A Non-Modal Dialog" - - val label: Label = new Label("

    " + - "This is a non-modal dialog.
    " + - "You can have one or more of these up
    " + - "and still use the main window.") { - horizontalAlignment = Alignment.Center - font = font.deriveFont(Font.PLAIN, 14.0f) - } - val closeButton: Button = new Button("Close") - - val closePanel = new BoxPanel(Orientation.Horizontal) { - contents += Swing.HGlue - contents += closeButton - border = Swing.EmptyBorder(0, 0, 5, 5) - } - - val contentPane: BorderPanel = new BorderPanel() { - layout(label) = BorderPanel.Position.Center - layout(closePanel) = BorderPanel.Position.South - opaque = true - } - contents = contentPane - listenTo(closeButton) - reactions += { - case ButtonClicked(`closeButton`) => - visible = false - dispose() - } - } - dialog.size = new Dimension(300, 150) - dialog.peer.setLocationRelativeTo(frame.peer) - dialog.visible = true - } - createPane(moreDialogDesc + ":", radioButtons, showItButton) - } - -} - -object DialogDemo extends SimpleSwingApplication { - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - - lazy val top = new MainFrame() { - title = "DialogDemo" - //Create and set up the content pane. - contents = new DialogDemo(this) - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala deleted file mode 100644 index 13b5141f..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FileChooserDemo.scala +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event._ - -import java.io.File - -/** - * Tutorial: How to Use File Choosers - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FileChooserDemoProject/src/components/FileChooserDemo.java]] - * - * FileChooserDemo.scala uses these files: - * /scala/swing/examples/tutorials/images/Open16.gif - * /scala/swing/examples/tutorials/images/Save16.gif - */ -class FileChooserDemo extends BorderPanel { - - val log = new TextArea(5, 20) { - peer.setMargin(new Insets(5, 5, 5, 5)) - editable = false - } - val logScrollPane = new ScrollPane(log) - - //Create a file chooser - val fc = new FileChooser() - - //Uncomment one of the following lines to try a different - //file selection mode. The first allows just directories - //to be selected (and, at least in the Java look and feel, - //shown). The second allows both files and directories - //to be selected. If you leave these lines commented out, - //then the default mode (FILES_ONLY) will be used. - // - //fc.fileSelectionMode = FileChooser.SelectionMode.DirectoriesOnly - //fc.fileSelectionMode = FileChooser.SelectionMode.FilesAndDirectories - //fc.fileSelectionMode = FileChooser.SelectionMode.FilesOnly - - //Create the open button. We use the image from the JLF - //Graphics Repository (but we extracted it from the jar). - val openButton = new Button("Open a File...") { - FileChooserDemo.createImageIcon("/scala/swing/examples/tutorials/images/Open16.gif").foreach( icn => - icon = icn - ) - } - - //Create the save button. We use the image from the JLF - //Graphics Repository (but we extracted it from the jar). - val saveButton = new Button("Save a File...") { - FileChooserDemo.createImageIcon("/scala/swing/examples/tutorials/images/Save16.gif").foreach( icn => - icon = icn - ) - } - - //For layout purposes, put the buttons in a separate panel - val buttonPanel = new FlowPanel() { - contents += openButton - contents += saveButton - } - - layout(buttonPanel) = BorderPanel.Position.North - layout(logScrollPane) = BorderPanel.Position.Center - - listenTo(openButton) - listenTo(saveButton) - - reactions += { - case ButtonClicked(`openButton`) => - fc.showOpenDialog(buttonPanel) match { - case FileChooser.Result.Approve => - val file: File = fc.selectedFile - //This is where a real application would open the file. - log.append(s"Opening: ${file.getName}.\n" ) - case _ => - log.append("Open command cancelled by user.\n") - } - - - case ButtonClicked(`saveButton`) => - fc.showSaveDialog(buttonPanel) match { - case FileChooser.Result.Approve => - val file: File = fc.selectedFile - //This is where a real application would save the file. - log.append(s"Saving: ${file.getName}.\n") - case _ => - log.append("Save command cancelled by user.\n") - } - } - -} - -object FileChooserDemo extends SimpleSwingApplication { - def createImageIcon(path: String ): Option[javax.swing.ImageIcon] = - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - - lazy val top = new MainFrame() { - title = "FileChooserDemo" - //Create and set up the content pane. - contents = new FileChooserDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala deleted file mode 100644 index c7374338..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FormattedTextFieldDemo.scala +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import java.text.NumberFormat -import java.awt.Color - -/* - * Tutorial: How to Use Formatted Text Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html - * - * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FormattedTextFieldDemoProject/src/components/FormattedTextFieldDemo.java - * - * FormattedTextFieldDemo.scala requires no other files. - * - * It implements a mortgage calculator that uses four JFormattedTextFields. - */ -class FormattedTextFieldDemo extends BorderPanel { - - //Values for the fields - private val amount: Double = 100000 - private val rate: Double = 7.5 //7.5% - private val numPeriods: Int = 30 - - //Labels to identify the fields - // private JLabel amountLabel - // private JLabel rateLabel - // private JLabel numPeriodsLabel - // private JLabel paymentLabel - - //Strings for the labels - private val amountString = "Loan Amount: " - private val rateString = "APR (%): " - private val numPeriodsString = "Years: " - private val paymentString = "Monthly Payment: " - - //Fields for data entry - // private JFormattedTextField amountField; - // private JFormattedTextField rateField; - // private JFormattedTextField numPeriodsField; - // private JFormattedTextField paymentField; - - //Formats to format and parse numbers - private val amountFormat: NumberFormat = NumberFormat.getNumberInstance() - private val percentFormat: NumberFormat = NumberFormat.getNumberInstance() - percentFormat.setMinimumFractionDigits(3) - private val paymentFormat: NumberFormat = NumberFormat.getCurrencyInstance() - - val payment = computePayment(amount, - rate, - numPeriods) - //Create the labels. - val amountLabel = new Label(amountString) - val rateLabel = new Label(rateString) - // val numPeriodsLabel = new Label(numPeriodsString) - val paymentLabel = new Label(paymentString) - - //Create the text fields and set them up. - val amountField = new FormattedTextField(amountFormat) { - // There are no instances of FormattedTextField that work... - // value = amount - // columns = 10 - } - val rateField = new FormattedTextField(percentFormat) { - // There are no instances of FormattedTextField that work... - // value = rate - // columns = 10 - } - // Format is obligatory in the scala constructors - // val numPeriodsField = new FormattedTextField() { - // There are no instances of FormattedTextField that work... - // value = numPeriods - // columns = 10 - // } - val paymentField = new FormattedTextField(paymentFormat) { - // There are no instances of FormattedTextField that work... - // value = payment - // columns = 10 - editable = false - foreground = Color.red - } - - //Tell accessibility tools about label/textfield pairs. - amountLabel.peer.setLabelFor(amountField.peer) - rateLabel.peer.setLabelFor(rateField.peer) - // numPeriodsLabel.peer.setLabelFor(numPeriodsField.peer) - paymentLabel.peer.setLabelFor(paymentField.peer) - - //Layout the labels in a panel - val labelPane = new GridPanel(0, 1) { - contents += amountLabel - contents += rateLabel - // contents += numPeriodsLabel - contents += paymentLabel - } - - //Layout the text fields in a panel. - val fieldPane = new GridPanel(0, 1) { - contents += amountField - contents += rateField - // contents += numPeriodsField - contents += paymentField - } - - //Put the panels in this panel, labels on left, - //text fields on right. - border = Swing.EmptyBorder(20, 20, 20, 20) - layout(labelPane) = BorderPanel.Position.Center - layout(fieldPane) = BorderPanel.Position.South - - listenTo(amountField) - listenTo(rateField) - // listenTo(numPeriodsField) -//What is the analogue of a PropertyChangeEvent? -// reactions += { -// } - - //Compute the monthly payment based on the loan amount, - //APR, and length of loan. - def computePayment(loanAmt: Double, rate: Double, numPeriodsYear: Int): Double = { - val numPeriods = 12 * numPeriodsYear //get number of months - val denominator = if (rate > 0.01) { - val I = rate / 100.0 / 12.0 //get monthly rate from annual - val partial1 = Math.pow((1 + I), (0.0 - numPeriods)) - (1 - partial1) / I - } else { //rate ~= 0 - numPeriods - } - (-1 * loanAmt) / denominator - } -} - -object FormattedTextFieldDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "FormattedTextFieldDemo" - //Create and set up the content pane. - javax.swing.UIManager.put("swing.boldMetal", false) - contents = new FormattedTextFieldDemo(); - } - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala deleted file mode 100644 index 1ed40e19..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/FrameDemo2.scala +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.ButtonClicked -import javax.swing.{ Box, BoxLayout, JDialog, JFrame, ImageIcon, UIManager } -import java.awt.{ BorderLayout, Color, Component, Dimension, Graphics, Image, Point, Toolkit } -import java.awt.image.BufferedImage -import java.net.URL - -/* - * Tutorial: How to Make Frames (Main Windows) - * http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html - * - * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemo2Project/src/components/FrameDemo2.java - * - * FrameDemo2.scala shows off the window decoration features added in - * 1.4, plus some window positioning code and (optionally) - * setIconImage. It uses the file /scala/swing/examples/tutorials/images/FD.jpg. - */ -class FrameDemo2 { - private var lastLocation: Point = null - private var defaultButton: Button = null - // private val maxX = 500 - // private val maxY = 500 - //constants for action commands - val NO_DECORATIONS = "no_dec"; - val LF_DECORATIONS = "laf_dec"; - val WS_DECORATIONS = "ws_dec"; - val CREATE_WINDOW = "new_win"; - val DEFAULT_ICON = "def_icon"; - val FILE_ICON = "file_icon"; - val PAINT_ICON = "paint_icon"; - - //true if the next frame created should have no window decorations - var noDecorations = false; - - //true if the next frame created should have setIconImage called - var specifyIcon = false; - - //true if the next frame created should have a custom painted icon - var createIcon = false; - - val screenSize: Dimension = Toolkit.getDefaultToolkit().getScreenSize() - val maxX = screenSize.width - 50 - val maxY = screenSize.height - 50 - - //Create a new MyFrame object and show it. - def showNewWindow(): Unit = { - //Take care of the no window decorations case. - //NOTE: Unless you really need the functionality - //provided by JFrame, you would usually use a - //Window or JWindow instead of an undecorated JFrame. - val frame: Option[Frame] = if (noDecorations) Some(new MyFrameUndecorated()) else Some(new MyFrame()) - //Set window location. - if (frame.isDefined) { - val f = frame.get - if (lastLocation != null) { - //Move the window over and down 40 pixels. - lastLocation.translate(40, 40); - if ((lastLocation.x > maxX) || (lastLocation.y > maxY)) { - lastLocation.setLocation(0, 0); - } - f.location = lastLocation - } else { - lastLocation = f.location - } - - //Calling setIconImage sets the icon displayed when the window - //is minimized. Most window systems (or look and feels, if - //decorations are provided by the look and feel) also use this - //icon in the window decorations. - if (specifyIcon) { - if (createIcon) { - //create an icon from scratch - f.iconImage = FrameDemo2.createFDImage() - } else { - //get the icon from a file - f.iconImage = FrameDemo2.getFDImage().get - } - } - } - } - - // Create the window-creation controls that go in the main window. - def createOptionControls(frame: Frame): BoxPanel = { - val label1 = new Label("Decoration options for subsequently created frames:") - val bg1 = new ButtonGroup() - val label2 = new Label("Icon options:") - val bg2 = new ButtonGroup() - - //Create the buttons - val rb1 = new RadioButton() { - text = "Look and feel decorated" - selected = true - } - bg1.buttons += rb1 - // - val rb2 = new RadioButton() { - text = "Window system decorated" - } - bg1.buttons += rb2 - // - val rb3 = new RadioButton() { - text = "No decorations" - } - bg1.buttons += rb3 - // - val rb4 = new RadioButton() { - text = "Default icon" - selected = true - } - bg2.buttons += rb4 - // - val rb5 = new RadioButton() { - text = "Icon from a JPEG file" - } - bg2.buttons += rb5 - // - val rb6 = new RadioButton() { - text = "Painted icon" - } - bg2.buttons += rb6 - - //Add everything to a container. - val box = new BoxPanel(Orientation.Vertical) { - border = Swing.EmptyBorder(10, 10, 10, 10) - contents += label1 - contents += Swing.VStrut(5) // spacer - contents += rb1 - contents += rb2 - contents += rb3 - contents += Swing.VStrut(15) - contents += label2 - contents += Swing.VStrut(5) - contents += rb4 - contents += rb5 - contents += rb6 - } - - frame.listenTo(rb1) - frame.listenTo(rb2) - frame.listenTo(rb3) - frame.listenTo(rb4) - frame.listenTo(rb5) - frame.listenTo(rb6) - frame.reactions += { - case ButtonClicked(`rb1`) => - noDecorations = false - JFrame.setDefaultLookAndFeelDecorated(true) - case ButtonClicked(`rb2`) => - noDecorations = false - JFrame.setDefaultLookAndFeelDecorated(false) - case ButtonClicked(`rb3`) => - noDecorations = true - // No need to set the default look and feel decorated property to false. - // JFrame.setDefaultLookAndFeelDecorated(false) - case ButtonClicked(`rb4`) => specifyIcon = false - case ButtonClicked(`rb5`) => - specifyIcon = true - createIcon = false - case ButtonClicked(`rb6`) => - specifyIcon = true - createIcon = true - } - - box - } - - //Create the button that goes in the main window. - def createButtonPane(frame: Frame): FlowPanel = { - val button = new Button("New window") - defaultButton = button - - frame.listenTo(button) - frame.reactions += { - case ButtonClicked(`button`) => showNewWindow() - } - - //Center the button in a panel with some space around it. - val pane = new FlowPanel() { - border = Swing.EmptyBorder(5, 5, 5, 5) - contents += button - } - pane - } - -} - -class MyFrame extends Frame { - title = "A window" - - //This button lets you close even an undecorated window. - val button = new Button("Close window") { - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - - //Place the button near the bottom of the window. - contents = new BoxPanel(Orientation.Vertical) { - contents += Swing.VGlue - contents += button - contents += Swing.VStrut(5) - } - // - listenTo(button) - reactions += { - case ButtonClicked(`button`) => - visible = false - dispose() - } - preferredSize = new Dimension(150, 150) - pack() - visible = true - override def closeOperation() = { - close - } -} - -class MyFrameUndecorated extends Frame with RichWindow.Undecorated { - visible = false - //This button lets you close even an undecorated window. - val button = new Button("Close window") { - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - - //Place the button near the bottom of the window. - //Undecorated windows are not supported in scala swing. - contents = new BoxPanel(Orientation.Vertical) { - contents += Swing.VGlue - contents += button - contents += Swing.VStrut(5) - } - // - listenTo(button) - reactions += { - case ButtonClicked(`button`) => - visible = false - dispose() - } - preferredSize = new Dimension(150, 150) - pack() - visible = true - override def closeOperation() = { - close - } -} - -object FrameDemo2 extends SimpleSwingApplication { - //Creates an icon-worthy Image from scratch. - def createFDImage(): Image = { - //Create a 16x16 pixel image. - val bi = new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB) - //Draw into it. - val g: Graphics = bi.getGraphics() - g.setColor(Color.BLACK); - g.fillRect(0, 0, 15, 15) - g.setColor(Color.RED) - g.fillOval(5, 3, 6, 6) - - //Clean up. - g.dispose() - - //Return it. - bi - } - - // Returns an Image Option or None. - def getFDImage(): Option[Image] = { - val imgURL: URL = getClass().getResource("/scala/swing/examples/tutorials/images/FD.jpg"); - if (imgURL != null) { - return Some(new ImageIcon(imgURL).getImage) - } else { - return None - } - } - - lazy val top = new Frame() { - title = "FrameDemo2" - //Use the Java look and feel. This needs to be done before the frame is created - //so the companion object FrameDemo2 cannot simply extend SimpleSwingApplcation. - try { - UIManager.setLookAndFeel( - UIManager.getCrossPlatformLookAndFeelClassName()); - } catch { - case e: Exception => ; - } - //Make sure we have nice window decorations. - JFrame.setDefaultLookAndFeelDecorated(true); - JDialog.setDefaultLookAndFeelDecorated(true); - //Create and set up the content pane. - val demo = new FrameDemo2(); - } - val bp: BorderPanel = new BorderPanel() { - layout(top.demo.createOptionControls(top)) = BorderPanel.Position.Center - layout(top.demo.createButtonPane(top)) = BorderPanel.Position.South - } - top.contents = bp - javax.swing.SwingUtilities.updateComponentTreeUI(top.peer) -} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala deleted file mode 100644 index 8f907f64..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ListDialog.scala +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import java.awt.Dimension -import java.awt.Font -import java.awt.Point -import java.awt._ -import scala.swing.Button -import scala.swing.Component -import scala.swing.Dialog -import scala.swing.Frame -import scala.swing.Label -import scala.swing.ScrollPane -import scala.swing._ -import scala.swing.event.{ButtonClicked, Key, MouseClicked} - -/** - * Tutorial: How to Use Buttons, Check Boxes, and Radio Buttons - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/button.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialogRunner.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ListDialogRunnerProject/src/components/ListDialog.java]] - */ -/** - * Use this modal dialog to let the user choose one string from a long - * list. See ListDialogRunner.scala for an example of using ListDialog. - * The basics: - *

    - * String[] choices = {"A", "long", "array", "of", "strings"};
    - * String selectedName = ListDialog.showDialog(
    - * componentInControllingFrame,
    - * locatorComponent,
    - * "A description of the list:",
    - * "Dialog Title",
    - * choices,
    - * choices[0]);
    - * 
    - */ -class ListDialog(frame: Frame, locationComp: Component, - labelText: String, title: String, data: Array[String], - initialValue: String, longValue: String) extends Dialog( frame, frame.peer.getGraphicsConfiguration) { - - // Must be a modal dialog. Otherwise the showDialog call will return - // immediately and the value returned will not reflect the user's - // selections. - peer.setModal(true) - val cancelButton = new Button("Cancel") - val setButton = new Button("Set") - val list = new ListView[String](data) { - if (longValue != null) { - prototypeCellValue = longValue - visibleRowCount = -1 - } - selection.intervalMode = ListView.IntervalMode.SingleInterval - } - list.peer.setLayoutOrientation(javax.swing.JList.HORIZONTAL_WRAP) - - val lSelect = list.selection - defaultButton = setButton - // - val listScroller = new ScrollPane(list) { - preferredSize = new Dimension(250, 80) - xLayoutAlignment = java.awt.Component.LEFT_ALIGNMENT - } - // - //Create a container so that we can add a title around - //the scroll pane. Can't add a title directly to the - //scroll pane because its background would be white. - //Lay out the label and scroll pane from top to bottom. - val label = new Label(labelText) - val listPane = new BoxPanel(Orientation.Vertical) { - border = Swing.EmptyBorder(10, 10, 10, 10) - contents += label - contents += Swing.RigidBox(new Dimension(0, 5)) - contents += listScroller - } - - val buttonPane = new BoxPanel(Orientation.Horizontal) { - border = Swing.EmptyBorder(10, 10, 10, 10) - contents += Swing.HGlue - contents += cancelButton - contents += Swing.RigidBox(new Dimension(10, 0)) - contents += setButton - } - - contents = new BorderPanel { - add(listPane, BorderPanel.Position.Center) - add(buttonPane, BorderPanel.Position.South) - } - - //Initialize values. - setValue(initialValue) - - // Events - listenTo(setButton) - listenTo(cancelButton) - listenTo(list.mouse.clicks) - reactions += { - case ButtonClicked(`setButton`) => - if (list.selection.leadIndex >= 0) setValue(list.listData(list.selection.leadIndex)) - visible = false - case ButtonClicked(`cancelButton`) => - setValue(initialValue) - visible = false - case MouseClicked(source: Component, point: Point, modifiers: Key.Modifiers, - clicks: Int, triggersPopup: Boolean) => if (clicks == 2) setButton.doClick() - } - // - pack() - setLocationRelativeTo(locationComp) - - private def setValue(newValue: String): Unit = { - ListDialog.value = newValue - } -} - -object ListDialog { - - var value: String = "" - - /** - * Set up and show the dialog. The first Component argument - * determines which frame the dialog depends on; it should be - * a component in the dialog's controlling frame. The second - * Component argument should be null if you want the dialog - * to come up with its left corner in the center of the screen; - * otherwise, it should be the component on top of which the - * dialog should appear. - */ - def showDialog(frameComp: Frame, locationComp: Component, - labelText: String, - title: String, - possibleValues: Array[String], - initialValue: String, - longValue: String): String = { - val dialog = new ListDialog(frameComp, locationComp, - labelText, title, possibleValues, initialValue, longValue) - dialog.visible = true - value - } -} - - -class ListDialogRunner(frame: Frame) extends BoxPanel(Orientation.NoOrientation) { - val names: Array[String] = Array("Arlo", "Cosmo", "Elmo", "Hugo", - "Jethro", "Laszlo", "Milo", "Nemo", - "Otto", "Ringo", "Rocco", "Rollo") - - //Create the labels. - val intro = new Label("The chosen name:") { - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - val nameLabel = new Label(names(1)) { - //Use a wacky font if it exists. If not, this falls - //back to a font we know exists. - font = getAFont - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - intro.peer.setLabelFor(nameLabel.peer) - - //Create the button. - val button = new Button("Pick a new name...") { - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - - listenTo(button) - reactions += { - case ButtonClicked(`button`) => - nameLabel.text = ListDialog.showDialog( - frame, - button, - "Baby names ending in 0:", - "Name chooser", - names.asInstanceOf[Array[String]], - nameLabel.text, - "Cosmo ") - - - } - - border = Swing.EmptyBorder(20, 20, 10, 20) - //Add the labels to the content pane. - contents += intro - contents += Swing.VStrut(5) - contents += nameLabel - //Add a vertical spacer that also guarantees us a minimum width: - contents += Swing.RigidBox(new Dimension(150, 10)) - contents += button - - - def getAFont: Font = { - //initial strings of desired fonts - val desiredFonts = Array[String]("French Script", "FrenchScript", "Bitstream Vera Sans") - //Search for all installed font families. The first - //call may take a while on some systems with hundreds of - //installed fonts, so if possible execute it in idle time, - //and certainly not in a place that delays painting of - //the UI (for example, when bringing up a menu). - // - //In systems with malformed fonts, this code might cause - //serious problems; use the latest JRE in this case. (You'll - //see the same problems if you use Swing's HTML support or - //anything else that searches for all fonts.) If this call - //causes problems for you under the latest JRE, please let - //us know. - val gEnv: GraphicsEnvironment = - GraphicsEnvironment.getLocalGraphicsEnvironment - val existingFamilyNames: Array[String] = gEnv.getAvailableFontFamilyNames - val chosenFonts: Array[Font] = - for { - desiredFont <- desiredFonts - existingFamilyName <- existingFamilyNames - if existingFamilyName.startsWith(desiredFont) - } yield new Font(existingFamilyName, Font.PLAIN, 30) - if (chosenFonts.nonEmpty) { - chosenFonts(0) - } else { - new Font("Serif", Font.ITALIC, 36) - } - } -} - -object ListDialogRunner extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "Name That Baby" - //Create and set up the content pane. - contents = new ListDialogRunner(this) - } -} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala deleted file mode 100644 index 78fc113c..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuDemo.scala +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR - * PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.{ ButtonClicked, Key } -import java.net.URL -import javax.swing.{ ImageIcon, KeyStroke } -import java.awt.event.{ ActionEvent, KeyEvent } - -/* - * Tutorial: How to Use Menus - * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html - * - * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuDemoProject/src/components/MenuDemo.java - * - * MenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. - * - * This class is just like MenuLookDemo, except the menu items - * actually do something, thanks to event listeners. - */ -class MenuDemo extends BorderPanel { - val output = new TextArea(5, 30) - val scrollPane = new ScrollPane(output) - layout(scrollPane) = BorderPanel.Position.Center - - def createMenuBar: MenuBar = { - //Create the menu bar. - val menuBar = new MenuBar() - //Build the fist menu. - val menu = new Menu("A Menu") { - mnemonic = Key.A - } - menu.peer.getAccessibleContext().setAccessibleDescription( - "The only menu in this program that has menu items") - menuBar.menus :+ menu - //a group of JMenuItems - val menuItem1 = new MenuItem(new Action("A text-only menu item") { - def apply() = {} - accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_1, ActionEvent.ALT_MASK)) - longDescription = "This doesn't really do anything" - }) { - mnemonic = Key.T - } - menu.contents += menuItem1 - // - val icon: ImageIcon = MenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val menuItem2 = new MenuItem("Both text and icon") { - icon = icon - mnemonic = Key.B - } - menu.contents += menuItem2 - // - val menuItem3 = new MenuItem("") { - icon = icon - mnemonic = Key.D - } - //a group of radio button menu items - menu.contents += new Separator(Orientation.Horizontal) - val group = new ButtonGroup() - // - val rbMenuItem1 = new RadioMenuItem("A radio button menu item") { - selected = true - mnemonic = Key.R - } - group.buttons += rbMenuItem1 - menu.contents += rbMenuItem1 - // - val rbMenuItem2 = new RadioMenuItem("Another one") { - mnemonic = Key.O - } - group.buttons += rbMenuItem2 - menu.contents += rbMenuItem2 - //a group of check box menu items - menu.contents += new Separator(Orientation.Horizontal) - val cbMenuItem1 = new CheckMenuItem("A check box menu item") { - mnemonic = Key.C - } - menu.contents += cbMenuItem1 - val cbMenuItem2 = new CheckMenuItem("Another one") { - mnemonic = Key.H - } - // - //a submenu - menu.contents += new Separator(Orientation.Horizontal) - val submenu = new Menu("A submenu") { - mnemonic = Key.S - } - val menuItemS1 = new MenuItem(new Action("An item in the submenu") { - def apply() = {} - accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_2, ActionEvent.ALT_MASK)) - }) - submenu.contents += menuItemS1 - // - val menuItemS2 = new MenuItem("Another item") - submenu.contents += menuItemS2 - menu.contents += submenu - // - //Build second menu in the menu bar. - val menu2 = new Menu("Another Menu") { - mnemonic = Key.N - } - menu2.peer.getAccessibleContext().setAccessibleDescription( - "This menu does nothing") - menuBar.contents += menu - menuBar.contents += menu2 - // - listenTo(menuItem1) - listenTo(menuItem2) - listenTo(menuItem3) - listenTo(rbMenuItem1) - listenTo(rbMenuItem2) - listenTo(cbMenuItem1) - listenTo(cbMenuItem2) - listenTo(menuItemS1) - reactions += { - case ButtonClicked(`menuItem1`) => actionPerformed(menuItem1) - case ButtonClicked(`menuItem2`) => actionPerformed(menuItem2) - case ButtonClicked(`menuItem3`) => actionPerformed(menuItem3) - case ButtonClicked(`rbMenuItem1`) => actionPerformed(rbMenuItem1) - case ButtonClicked(`rbMenuItem2`) => actionPerformed(rbMenuItem2) - case ButtonClicked(`cbMenuItem1`) => actionPerformed(cbMenuItem1) - case ButtonClicked(`cbMenuItem2`) => actionPerformed(cbMenuItem2) - case ButtonClicked(`menuItemS1`) => actionPerformed(menuItemS1) - case ButtonClicked(`menuItemS2`) => actionPerformed(menuItemS2) - // No ItemEvents in scala.swing.... - // case SelectionChanged(`menuItem1`) => itemStateChanged(menuItem1) - // case SelectionChanged(`menuItem2`) => itemStateChanged(menuItem2) - // case SelectionChanged(`menuItem3`) => itemStateChanged(menuItem3) - // case SelectionChanged(`rbMenuItem1`) => itemStateChanged(rbMenuItem1) - // case SelectionChanged(`rbMenuItem2`) => itemStateChanged(rbMenuItem2) - // case SelectionChanged(`cbMenuItem1`) => itemStateChanged(cbMenuItem1) - // case SelectionChanged(`cbMenuItem2`) => itemStateChanged(cbMenuItem2) - // case SelectionChanged(`menuItemS1`) => itemStateChanged(menuItemS1) - // case SelectionChanged(`menuItemS2`) => itemStateChanged(menuItemS2) - } - menuBar - } - - def actionPerformed(source: MenuItem): Unit = { - val newline = "\n" - val s = "Action event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")"; - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() - } - - def itemStateChanged(source: MenuItem): Unit = { - val newline = "\n" - val s = "Item event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")" + - newline + - " New state: " + - (if (source.selected) "selected" else "unselected") - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() - } - - // Returns just the class name -- no package info. - def getClassName(o: AnyRef): String = { - val classString = o.getClass().getName() - val dotIndex = classString.lastIndexOf(".") - classString.substring(dotIndex + 1) - } -} - -object MenuDemo extends SimpleSwingApplication { - /** Returns an ImageIcon icon, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } - } - lazy val top = new MainFrame() { - title = "MenuDemo" - //Create and set up the content pane. - val newContentPane = new MenuDemo(); - menuBar = newContentPane.createMenuBar - contents = newContentPane - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala deleted file mode 100644 index 5b6f81fc..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/MenuLookDemo.scala +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR - * PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.Key -import java.net.URL -import javax.swing.{ ImageIcon, KeyStroke } -import java.awt.event.{ ActionEvent, KeyEvent } - -/* - * Tutorial: How to Use Menus - * http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html - * - * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/MenuLookDemoProject/src/components/MenuLookDemo.java - * - * MenuLookDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. - * - * This class exists solely to show you what menus look like. - * It has no menu-related event handling. - */ -class MenuLookDemo extends BorderPanel { - val output = new TextArea(5, 30) - val scrollPane = new ScrollPane(output) - layout(scrollPane) = BorderPanel.Position.Center - - def createMenuBar: MenuBar = { - //Create the menu bar. - val menuBar = new MenuBar() - //Build the fist menu. - val menu = new Menu("A Menu") { - mnemonic = Key.A - } - menu.peer.getAccessibleContext().setAccessibleDescription( - "The only menu in this program that has menu items") - menuBar.menus :+ menu - //a group of JMenuItems - val menuItem1 = new MenuItem(new Action("A text-only menu item") { - def apply() = {} - accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_1, ActionEvent.ALT_MASK)) - longDescription = "This doesn't really do anything" - }) { - mnemonic = Key.T - } - menu.contents += menuItem1 - // - val icon: ImageIcon = MenuLookDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val menuItem2 = new MenuItem("Both text and icon") { - icon = icon - mnemonic = Key.B - } - menu.contents += menuItem2 - // - val menuItem3 = new MenuItem("") { - icon = icon - mnemonic = Key.D - } - //a group of radio button menu items - menu.contents += new Separator(Orientation.Horizontal) - val group = new ButtonGroup() - // - val rbMenuItem1 = new RadioMenuItem("A radio button menu item") { - selected = true - mnemonic = Key.R - } - group.buttons += rbMenuItem1 - menu.contents += rbMenuItem1 - // - val rbMenuItem2 = new RadioMenuItem("Another one") { - mnemonic = Key.O - } - group.buttons += rbMenuItem2 - menu.contents += rbMenuItem2 - //a group of check box menu items - menu.contents += new Separator(Orientation.Horizontal) - val cbMenuItem1 = new CheckMenuItem("A check box menu item") { - mnemonic = Key.C - } - menu.contents += cbMenuItem1 - val cbMenuItem2 = new CheckMenuItem("Another one") { - mnemonic = Key.H - } - // - //a submenu - menu.contents += new Separator(Orientation.Horizontal) - val submenu = new Menu("A submenu") { - mnemonic = Key.S - } - val menuItemS1 = new MenuItem(new Action("An item in the submenu") { - def apply() = {} - accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_2, ActionEvent.ALT_MASK)) - }) - submenu.contents += menuItemS1 - // - val menuItemS2 = new MenuItem("Another item") - submenu.contents += menuItemS2 - menu.contents += submenu - // - //Build second menu in the menu bar. - val menu2 = new Menu("Another Menu") { - mnemonic = Key.N - } - menu2.peer.getAccessibleContext().setAccessibleDescription( - "This menu does nothing") - menuBar.contents += menu - menuBar.contents += menu2 - menuBar - } - - def actionPerformed(source: MenuItem) { - val newline = "\n" - val s = "Action event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")"; - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() - } - - def itemStateChanged(source: MenuItem) { - val newline = "\n" - val s = "Item event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")" + - newline + - " New state: " + - (if (source.selected) "selected" else "unselected") - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() - } - - // Returns just the class name -- no package info. - def getClassName(o: AnyRef) { - val classString = o.getClass().getName() - val dotIndex = classString.lastIndexOf(".") - classString.substring(dotIndex + 1) - } -} - -object MenuLookDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } - } - - lazy val top = new MainFrame() { - title = "MenuLookDemo" - //Create and set up the content pane. - val newContentPane = new MenuLookDemo() { - opaque = true - } - menuBar = newContentPane.createMenuBar - contents = newContentPane - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala deleted file mode 100644 index d635e0ee..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/PopupMenuDemo.scala +++ /dev/null @@ -1,266 +0,0 @@ - -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.{ButtonClicked, Key, MousePressed, MouseReleased} -import java.net.URL -import javax.swing.{ ImageIcon, KeyStroke } -import java.awt.event.{ ActionEvent, KeyEvent } -import java.awt.Point - -/* - * Tutorial: How to Use Password Fields - * http://docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html - * - * Source code reference: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/PopupMenuDemoProject/src/components/PopupMenuDemo.java - * - * PopupMenuDemo.scala requires /scala/swing/examples/tutorials/images/middle.gif. - * - * Like MenuDemo, but with popup menus added. - */ -class PopupMenuDemo extends BorderPanel { - val output = new TextArea(5, 30) - val scrollPane = new ScrollPane(output) - layout(scrollPane) = BorderPanel.Position.Center - - listenTo(output.mouse.clicks) - - def createMenuBar: MenuBar = { - //Create the menu bar. - val menuBar = new MenuBar() - //Build the fist menu. - val menu = new Menu("A Menu") { - mnemonic = Key.A - } - menu.peer.getAccessibleContext().setAccessibleDescription( - "The only menu in this program that has menu items") - menuBar.menus :+ menu - //a group of JMenuItems - val menuItem1 = new MenuItem(new Action("A text-only menu item") { - def apply() = {} - accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_1, ActionEvent.ALT_MASK)) - longDescription = "This doesn't really do anything" - }) { - mnemonic = Key.T - } - menu.contents += menuItem1 - // - val icon: ImageIcon = PopupMenuDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val menuItem2 = new MenuItem("Both text and icon") { - icon = icon - mnemonic = Key.B - } - menu.contents += menuItem2 - // - val menuItem3 = new MenuItem("") { - icon = icon - mnemonic = Key.D - } - //a group of radio button menu items - menu.contents += new Separator(Orientation.Horizontal) - val group = new ButtonGroup() - // - val rbMenuItem1 = new RadioMenuItem("A radio button menu item") { - selected = true - mnemonic = Key.R - } - group.buttons += rbMenuItem1 - menu.contents += rbMenuItem1 - // - val rbMenuItem2 = new RadioMenuItem("Another one") { - mnemonic = Key.O - } - group.buttons += rbMenuItem2 - menu.contents += rbMenuItem2 - //a group of check box menu items - menu.contents += new Separator(Orientation.Horizontal) - val cbMenuItem1 = new CheckMenuItem("A check box menu item") { - mnemonic = Key.C - } - menu.contents += cbMenuItem1 - val cbMenuItem2 = new CheckMenuItem("Another one") { - mnemonic = Key.H - } - // - //a submenu - menu.contents += new Separator(Orientation.Horizontal) - val submenu = new Menu("A submenu") { - mnemonic = Key.S - } - val menuItemS1 = new MenuItem(new Action("An item in the submenu") { - def apply() = {} - accelerator = Some(KeyStroke.getKeyStroke( - KeyEvent.VK_2, ActionEvent.ALT_MASK)) - }) - submenu.contents += menuItemS1 - // - val menuItemS2 = new MenuItem("Another item") - submenu.contents += menuItemS2 - menu.contents += submenu - // - //Build second menu in the menu bar. - val menu2 = new Menu("Another Menu") { - mnemonic = Key.N - } - menu2.peer.getAccessibleContext().setAccessibleDescription( - "This menu does nothing") - menuBar.contents += menu - menuBar.contents += menu2 - // - listenTo(menuItem1) - listenTo(menuItem2) - listenTo(menuItem3) - listenTo(rbMenuItem1) - listenTo(rbMenuItem2) - listenTo(cbMenuItem1) - listenTo(cbMenuItem2) - listenTo(menuItemS1) - reactions += { - case ButtonClicked(`menuItem1`) => actionPerformed(menuItem1) - case ButtonClicked(`menuItem2`) => actionPerformed(menuItem2) - case ButtonClicked(`menuItem3`) => actionPerformed(menuItem3) - case ButtonClicked(`rbMenuItem1`) => actionPerformed(rbMenuItem1) - case ButtonClicked(`rbMenuItem2`) => actionPerformed(rbMenuItem2) - case ButtonClicked(`cbMenuItem1`) => actionPerformed(cbMenuItem1) - case ButtonClicked(`cbMenuItem2`) => actionPerformed(cbMenuItem2) - case ButtonClicked(`menuItemS1`) => actionPerformed(menuItemS1) - case ButtonClicked(`menuItemS2`) => actionPerformed(menuItemS2) - // No ItemEvents in scala.swing.... - // case SelectionChanged(`menuItem1`) => itemStateChanged(menuItem1) - // case SelectionChanged(`menuItem2`) => itemStateChanged(menuItem2) - // case SelectionChanged(`menuItem3`) => itemStateChanged(menuItem3) - // case SelectionChanged(`rbMenuItem1`) => itemStateChanged(rbMenuItem1) - // case SelectionChanged(`rbMenuItem2`) => itemStateChanged(rbMenuItem2) - // case SelectionChanged(`cbMenuItem1`) => itemStateChanged(cbMenuItem1) - // case SelectionChanged(`cbMenuItem2`) => itemStateChanged(cbMenuItem2) - // case SelectionChanged(`menuItemS1`) => itemStateChanged(menuItemS1) - // case SelectionChanged(`menuItemS2`) => itemStateChanged(menuItemS2) - } - menuBar - } - - def actionPerformed(source: MenuItem) { - val newline = "\n" - val s = "Action event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")"; - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() - } - - def itemStateChanged(source: MenuItem) { - val newline = "\n" - val s = "Item event detected." + - newline + - " Event source: " + source.text + - " (an instance of " + getClassName(source) + ")" + - newline + - " New state: " + - (if (source.selected) "selected" else "unselected") - output.append(s + newline); - output.caret.position = output.peer.getDocument().getLength() - } - - // Returns just the class name -- no package info. - def getClassName(o: AnyRef) { - val classString = o.getClass().getName() - val dotIndex = classString.lastIndexOf(".") - classString.substring(dotIndex + 1) - } - - def createPopupMenu(): Unit = { - //Create the popup menu. - val menuItem1P = new MenuItem("A popup menu item") - val menuItem2P = new MenuItem("Another popup menu item") - val popup = new PopupMenu() { - contents += menuItem1P - contents += menuItem2P - } - //Add listener to the text area so the popup menu can come up. - // MouseListener popupListener = new PopupListener(popup); - // output.addMouseListener(popupListener); - - listenTo(menuItem1P) - listenTo(menuItem2P) - reactions += { - case ButtonClicked(`menuItem1P`) => actionPerformed(menuItem1P) - case ButtonClicked(`menuItem2P`) => actionPerformed(menuItem2P) - // No ItemEvents in scala.swing.... - // case SelectionChanged(`menuItem1P`) => itemStateChanged(menuItem1P) - // case SelectionChanged(`menuItem2P`) => itemStateChanged(menuItem2P) - case MousePressed(source: Component, point: Point, modifiers: Key.Modifiers, - clicks: Int, triggersPopup: Boolean) => maybeShowPopup(popup, source, point, triggersPopup) - case MouseReleased(source: Component, point: Point, modifiers: Key.Modifiers, - clicks: Int, triggersPopup: Boolean) => maybeShowPopup(popup, source, point, triggersPopup) - } - } - - def maybeShowPopup(popup: PopupMenu, c: Component, p: Point, isPopupTrigger: Boolean): Unit = { - if (isPopupTrigger) { - popup.show(c, p.getX().toInt, p.getY().toInt) - } - } -} - -object PopupMenuDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[ImageIcon] = { - val imgURL: URL = getClass().getResource(path) - if (imgURL != null) { - Some(Swing.Icon(imgURL)) - } else { - None - } - } - /** - * Create the GUI and show it. - */ - lazy val top = new MainFrame() { - title = "PopupMenuDemo" - //Create and set up the content pane. - val demo = new PopupMenuDemo() { - opaque = true - } - menuBar = demo.createMenuBar - contents = demo - //Create and set up the popup menu. - demo.createPopupMenu() - - //Display the window. - size = new Dimension(450, 260) - } - -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala deleted file mode 100644 index 12509766..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo.scala +++ /dev/null @@ -1,299 +0,0 @@ - -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -//import java.awt._ - -import java.awt.{Dimension, Toolkit, Color, Font} - -import scala.swing._ -import javax.swing.{SwingConstants, ImageIcon, ScrollPaneConstants} -import scala.swing.Component -import scala.swing.event.{MouseDragged, Key, MouseMoved, ButtonClicked} - -/* - * Tutorial: How to Use Scroll Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html - * - * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollDemo.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Rule.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/Corner.java - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemoProject/src/components/ScrollablePicture.java - * - * ScrollDemo.scala requires these files: - * Rule.scala - * Corner.scala - * ScrollablePicture.scala - * /scala/swing/examples/tutorials/images/flyingBee.jpg - */ -class ScrollDemo extends BoxPanel(Orientation.Horizontal) { - //Get the image to use. - val beeOp: Option[ImageIcon] = ScrollDemo.createImageIcon("/scala/swing/examples/tutorials/images/scala-stairs.jpg") - - //Create the row and column headers. - val columnView = new Rule(Rule.Horizontal, true) - val rowView = new Rule(Rule.Vertical, true) - - beeOp match { - case Some( bee ) => - columnView.preferredWidth = bee.getIconWidth - rowView.preferredHeight = bee.getIconHeight - case None => - columnView.preferredWidth = 320 - rowView.preferredWidth = 480 - } - - //Create the corners. - val isMetric = new ToggleButton("cm") { - selected = true - font = new Font("SansSerif", Font.PLAIN, 11) - margin = new Insets(2, 2, 2, 2) - } - val buttonCorner = new FlowPanel() { - contents += isMetric - } - - //Set up the scroll pane. - val picture = new ScrollablePicture(beeOp, columnView.increment) - val pictureScrollPane = new ScrollPane(picture) { - preferredSize = new Dimension(300, 250) - columnHeaderView = columnView - rowHeaderView = rowView - } - pictureScrollPane.peer.setViewportBorder(Swing.LineBorder(Color.black)) - - //Set the corners. - //In theory, to support internationalization you would change - //UPPER_LEFT_CORNER to UPPER_LEADING_CORNER, - //LOWER_LEFT_CORNER to LOWER_LEADING_CORNER, and - //UPPER_RIGHT_CORNER to UPPER_TRAILING_CORNER. In practice, - //bug #4467063 makes that impossible (in 1.4, at least). - pictureScrollPane.peer.setCorner(ScrollPaneConstants.UPPER_LEADING_CORNER, buttonCorner.peer) - pictureScrollPane.peer.setCorner(ScrollPaneConstants.LOWER_LEADING_CORNER, new Corner()) - pictureScrollPane.peer.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, new Corner()) - - contents += pictureScrollPane - border = Swing.EmptyBorder(20, 20, 20, 20) - - listenTo(isMetric) - // Original had an itemListener. Scala Swing makes no provision - // for item changed events, so use button clicked instead. - reactions += { - case ButtonClicked(`isMetric`) => if (isMetric.selected) { - // Turn it to metric.. - rowView.setIsMetric(true) - columnView.setIsMetric(true) - } else { - // Turn it to inches. - rowView.setIsMetric(false) - columnView.setIsMetric(false) - } - picture.setMaxUnitIncrement(rowView.increment) - } -} - -object ScrollDemo extends SimpleSwingApplication { - def createImageIcon(path: String ): Option[javax.swing.ImageIcon] = - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - - lazy val top = new MainFrame() { - title = "ScrollDemo" - contents = new ScrollDemo() - } -} - - - - - -class ScrollablePicture(img: Option[ImageIcon], var maxUnitIncrement: Int) extends ScrollPane( new Label("", img.orNull, Alignment.Center)) { - - private var missingPicture = false - - if( img == None) { - missingPicture = true -// text = "No picture found." -// horizontalAlignment = Alignment.Center - opaque = true - background = Color.white - } - - //Let the user scroll by dragging to outside the window. - peer.setAutoscrolls(true) - listenTo(mouse.moves) - reactions += { - case MouseMoved(source: Component, point: Point, modifiers: Key.Modifiers) => - peer.scrollRectToVisible(new Rectangle(point.x, point.y)) - case MouseDragged(source: Component, point: Point, modifiers: Key.Modifiers) => - peer.scrollRectToVisible(new Rectangle(point.x, point.y)) - } - - def getPreferredScrollableViewportSize: Dimension = - if (missingPicture) new Dimension(320, 480) - else preferredSize - - - def getScrollableUnitIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { - //Get the current position. - val currentPosition = - if (orientation == SwingConstants.HORIZONTAL) visibleRect.x - else visibleRect.y - - - //Return the number of pixels between currentPosition - //and the nearest tick mark in the indicated direction. - if (direction < 0) { - val newPosition = currentPosition - (currentPosition / maxUnitIncrement) * maxUnitIncrement - if (newPosition == 0) maxUnitIncrement else newPosition - } else { - ((currentPosition / maxUnitIncrement) + 1) * maxUnitIncrement -currentPosition - } - } - - def getScrollableBlockIncrement(visibleRect: Rectangle, orientation: Int, direction: Int): Int = { - if (orientation == SwingConstants.HORIZONTAL) - visibleRect.width - maxUnitIncrement - else - visibleRect.height - maxUnitIncrement - } - - def scrollableTracksViewportWidth: Boolean = false - - def scrollableTracksViewportHeight: Boolean = false - - def setMaxUnitIncrement(pixels: Int): Unit = { - maxUnitIncrement = pixels - } -} - - - -class Rule(val orientation: Int, var isMetric: Boolean) extends Component { - val Inch: Int = Toolkit.getDefaultToolkit.getScreenResolution - val Size = 35 - - def units = - if (isMetric) (Inch.toDouble / 2.54).toInt // dots per centimeter - else Inch - - def increment = if (isMetric) units else units / 2 - - def setIsMetric(isMetricArg: Boolean): Unit = { - isMetric = isMetricArg - repaint() - } - - - // def setPreferredHeight(ph: Int): Unit = { - // preferredSize = new Dimension(Size, ph) - // } - // def setPreferredWidth(pw: Int): Unit = { - // preferredSize = new Dimension(pw, Size) - // } - - - def preferredHeight = preferredSize.height - def preferredHeight_=(ph: Int): Unit = preferredSize = new Dimension(Size, ph) - - def preferredWidth = preferredSize.width - def preferredWidth_=(pw: Int): Unit = preferredSize = new Dimension(pw, Size) - - - override def paintComponent(g: Graphics2D): Unit = { - val drawHere: Rectangle = g.getClipBounds - - // Fill clipping area with dirty brown/orange. - g.setColor(new Color(230, 163, 4)) - g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height) - - // Do the ruler labels in a small font that's black. - g.setFont(new Font("SansSerif", Font.PLAIN, 10)) - g.setColor(Color.black) - - // Some vars we need. - var tickLength = 0 - var text: String = null - - // Use clipping bounds to calculate first and last tick locations. - var (start, end) = - if (orientation == Rule.Horizontal) - ( (drawHere.x / increment) * increment, (((drawHere.x + drawHere.width) / increment) + 1) * increment ) - else - ( (drawHere.y / increment) * increment, (((drawHere.y + drawHere.height) / increment) + 1) * increment ) - - // Make a special case of 0 to display the number - // within the rule and draw a units label. - if (start == 0) { - val u = if (isMetric) " cm" else " in" - text = Integer.toString(0) + u - tickLength = 10 - - if (orientation == Rule.Horizontal) { - drawText(0, Some(text), (0, Size - 1), (0, Size - tickLength - 1), (2, 21)) - } else { - drawText(0, Some(text), (Size - 1, 0), (Size - tickLength - 1, 0), (9, 10)) - } - text = null - start = increment - } - - // ticks and labels - for (i <- start until end by increment) { - - val(tickLength, text ) = - if(i % units == 0 ) (10, Some(Integer.toString(i / units) )) - else (7, None) - - - if (tickLength != 0) { - if (orientation == Rule.Horizontal) drawText(i, text, (i, Size - 1), (i, Size - tickLength - 1), (i - 3, 21)) - else drawText(i, text, (Size - 1, i), (Size - tickLength - 1, i), (9, i + 3)) - } - } - - - def drawText(i:Int, text:Option[String], lineFrom:(Int, Int), lineTo:(Int, Int), txtLoc:(Int, Int) ): Unit = { - g.drawLine(lineFrom._1, lineFrom._2, lineTo._1, lineTo._2) - text.foreach( txt => g.drawString(txt, txtLoc._1, txtLoc._2)) - - } - - - } - -} - -object Rule { - val Horizontal = 0 - val Vertical = 1 -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala deleted file mode 100644 index e01f4f0c..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/ScrollDemo2.scala +++ /dev/null @@ -1,140 +0,0 @@ - -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.MouseReleased -import javax.swing.SwingUtilities -import java.awt.{Color, Dimension, Graphics2D, Rectangle} - -/* - * Tutorial: How to Use Scroll Panes - * http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html - * - * Source code references: - * http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ScrollDemo2Project/src/components/ScrollDemo2.java - * - * ScrollDemo2.scala requires no other files. - */ -class ScrollDemo2 extends BorderPanel { - val colors: Array[Color] = Array( - Color.red, Color.blue, Color.green, Color.orange, - Color.cyan, Color.magenta, Color.darkGray, Color.yellow) - var circles = Seq[Rectangle]() - - //Set up the instructions - val instructionsLeft = new Label("Click left mouse button to place a circle.") - val instructionsRight = new Label("Click right mouse button to clear drawing area.") - val instructionPanel = new GridPanel(0, 1) { - focusable = true - contents += instructionsLeft - contents += instructionsRight - } - - //Set up the drawing area. - val drawingPane = new DrawingPane() { - background = Color.white - } - - //Put the drawing area in a scroll pane. - val scroller = new ScrollPane(drawingPane) { - preferredSize = new Dimension(200, 200) - } - layout(instructionPanel) = BorderPanel.Position.North - layout(scroller) = BorderPanel.Position.Center - - /** The component inside the scroll pane. */ - class DrawingPane extends Panel { -// background = Color.white Definitely not. - preferredSize = new Dimension(200, 200) - focusable = true - val area = new Dimension() - override def paintComponent(g: Graphics2D): Unit = { - super.paintComponent(g); - for (i <- 0 until circles.length) { - val rect: Rectangle = circles(i) - g.setColor(colors((i % colors.length))) - g.fillOval(rect.x, rect.y, rect.width, rect.height); - } - } - listenTo(mouse.clicks) - listenTo(mouse.moves) - listenTo(keys) - reactions += { - case e: MouseReleased => - circles = Seq[Rectangle]() - val W = 100 - val H = 100 - var changed = false - if (SwingUtilities.isRightMouseButton(e.peer)) { - //This will clear the graphic objects. - circles = Seq[Rectangle]() - area.width = 0; - area.height = 0; - changed = true; - } else { - val x = if (e.point.x >= W / 2) e.point.x - W / 2 else 0 - val y = if (e.point.y >= H / 2) e.point.y - H / 2 else 0 - val rect = new Rectangle(x, y, W, H) - circles = circles :+ rect - drawingPane.peer.scrollRectToVisible(rect) - changed = x + W + 2 > area.width - if (changed) { - area.width = x + W + 2 - } - if (y + H + 2 > area.height) { - area.width = y + H + 2 - changed = true - } - if (changed) { - //Update client's preferred size because - //the area taken up by the graphics has - //gotten larger or smaller (if cleared). - preferredSize = area - - //Let the scroll pane know to update itself - //and its scrollbars. - revalidate(); - } - } - repaint() - } - } - -} - -object ScrollDemo2 extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "ScrollDemo2" - contents = new ScrollDemo2() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala deleted file mode 100644 index df039ae2..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableDemo.scala +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.MouseClicked -/* - * Tutorial: How to Use Tables - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java]] - * - * SimpleTableDemo.scala requires no other files. - */ -class SimpleTableDemo extends GridPanel(1, 0) { - private val Debug = false - val columnNames: Array[String] = Array("First Name", - "Last Name", - "Sport", - "# of Years", - "Vegetarian") - val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", 5, false) - data(1) = Array("John", "Doe", "Rowing", 3, true) - data(2) = Array("Sue", "Black", "Knitting", 2, false) - data(3) = Array("Jane", "White", "Speed reading", 20, true) - data(4) = Array("Joe", "Brown", "Pool", 10, false) - - val table = new Table(data, columnNames) { - preferredViewportSize = new Dimension(500, 70) - } - table.peer.setFillsViewportHeight(true) - if (Debug) { - listenTo(table) - reactions += { - case e: MouseClicked => printDebugData(table) - } - } - - //Create the scroll pane and add the table to it. - val scrollPane = new ScrollPane(table) - - //Add the scroll pane to this panel. - contents += scrollPane - - private def printDebugData(table: Table): Unit = { - val numRows = table.rowCount - val numCols = table.peer.getColumnCount - val model: javax.swing.table.TableModel = table.model - - println("Value of data: ") - for (i <- 0 until numRows) { - System.out.print(" row " + i + ":") - for (j <- 0 until numCols) { - print(" " + model.getValueAt(i, j)) - } - println() - } - println("--------------------------") - } -} - -object SimpleTableDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "SimpleTableDemo" - contents = new SimpleTableDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala deleted file mode 100644 index c4be6abc..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SimpleTableSelectionDemo.scala +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - - -import scala.swing._ -import scala.collection.immutable.Range -import scala.swing.event.{ MouseClicked, TableColumnsSelected, TableRowsSelected } - -/** - * Tutorial: How to Use Tables - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableSelectionDemoProject/src/components/SimpleTableSelectionDemo.java]] - * - * SimpleTableSelectionDemo.scala requires no other files. - */ -class SimpleTableSelectionDemo extends GridPanel(1, 0) { - private val Debug = true - private val AllowColumnSelection = false - private val AllowRowSelection = true - - val columnNames: Array[String] = Array("First Name", - "Last Name", - "Sport", - "# of Years", - "Vegetarian") - - val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", 5, false) - data(1) = Array("John", "Doe", "Rowing", 3, true) - data(2) = Array("Sue", "Black", "Knitting", 2, false) - data(3) = Array("Jane", "White", "Speed reading", 20, true) - data(4) = Array("Joe", "Brown", "Pool", 10, false) - - val table = new Table(data, columnNames) { - preferredViewportSize = new Dimension(500, 70) - selection.intervalMode = Table.IntervalMode.Single - } - table.peer.setFillsViewportHeight(true) - - if (AllowRowSelection) { - listenTo(table.selection) - reactions += { - case TableRowsSelected(`table`, range: Range, adjusting: Boolean) => - //Ignore extra messages. - if (!adjusting) { - if (range.isEmpty) { - println("No rows are selected.") - } else { - val selectedRow = range.head - println("Row " + selectedRow + " is now selected.") - } - } - } - } else { - if (table.selection.elementMode == Table.ElementMode.Cell) { - table.selection.elementMode = Table.ElementMode.Column - } else if (table.selection.elementMode == Table.ElementMode.Row) { - table.selection.elementMode = Table.ElementMode.None - } - } - - if (AllowColumnSelection) { // false by default - if (AllowRowSelection || table.selection.elementMode == Table.ElementMode.Row) { - //We allow both row and column selection, which - //implies that we *really* want to allow individual - //cell selection. - table.selection.elementMode = Table.ElementMode.Cell - } else if (table.selection.elementMode == Table.ElementMode.None) { - table.selection.elementMode = Table.ElementMode.Column - } - listenTo(table.selection) - reactions += { - case TableColumnsSelected(`table`, range: Range, adjusting: Boolean) => - //Ignore extra messages. - if (!adjusting) { - if (range.isEmpty) println("No rows are selected.") - else println(s"Column ${range.head} is now selected.") - } - } - } - if (Debug) { - listenTo(table) - reactions += { - case e: MouseClicked => printDebugData(table) - } - } - - //Create the scroll pane and add the table to it. - val scrollPane = new ScrollPane(table) - - //Add the scroll pane to this panel. - contents += scrollPane - - private def printDebugData(table: Table): Unit = { - val numRows = table.rowCount - val numCols = table.peer.getColumnCount - val model: javax.swing.table.TableModel = table.model - - println("Value of data: ") - for (i <- 0 until numRows) { - print(" row " + i + ":") - for (j <- 0 until numCols) { - print(" " + model.getValueAt(i, j)) - } - println() - } - println("--------------------------") - } -} - -object SimpleTableSelectionDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "SimpleTableSelectionDemo" - contents = new SimpleTableSelectionDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala deleted file mode 100644 index 70388180..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SizeDisplayer.scala +++ /dev/null @@ -1,150 +0,0 @@ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import java.awt.{ AlphaComposite, Color, Composite, Graphics, Insets, RenderingHints } -import java.awt.font.FontRenderContext -import java.awt.geom.Rectangle2D -import javax.swing.Icon - -class SizeDisplayer(text: String, icon: Icon) extends Label(text, icon, Alignment.Center) { - val xTextPad = 5 - val yTextPad = 5 - opaque = true - - //Reuse textSizeD and textSizeR to avoid creating - //lots of unnecessary Dimensions and Rectangles. - private var textSizeR = new Rectangle() - private var textSizeD = new Dimension() - private var userPreferredSize: Dimension = null - private var userMinimumSize: Dimension = null - private var userMaximumSize: Dimension = null - - def paintComponent(g: Graphics): Unit = { - val g2d = g.create().asInstanceOf[Graphics2D] //copy g - var prefX = 0 - var prefY = 0; - - //Set hints so text looks nice. - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON) - g2d.setRenderingHint(RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY) - - //Draw the maximum size rectangle if we're opaque. - if (opaque) { - g2d.setColor(super.background) - g2d.fillRect(0, 0, size.width, size.height) - } - - //Draw the icon. - if (icon != null) { - val oldComposite: Composite = g2d.getComposite(); - g2d.setComposite(AlphaComposite.getInstance( - AlphaComposite.SRC_OVER, - 0.1f)) - icon.paintIcon(peer, g2d, - (size.width - icon.getIconWidth()) / 2, - (size.height - icon.getIconHeight()) / 2) - g2d.setComposite(oldComposite) - } - - //Draw the preferred size rectangle. - prefX = (size.width - preferredSize.width) / 2 - prefY = (size.height - preferredSize.height) / 2 - g2d.setColor(Color.RED) - g2d.drawRect(prefX, prefY, preferredSize.width - 1, preferredSize.height - 1) - - //Draw the minimum size rectangle. - if (minimumSize.width != preferredSize.width || minimumSize.height != preferredSize.height) { - val minX = (size.width - minimumSize.width) / 2 - val minY = (size.height - minimumSize.height) / 2 - g2d.setColor(Color.CYAN) - g2d.drawRect(minX, minY, minimumSize.width - 1, minimumSize.height - 1) - } - - //Draw the text. - if (text != null) { - val textSize: Dimension = getTextSize(g2d) - g2d.setColor(peer.getForeground()) - g2d.drawString(text, - (size.width - textSize.width) / 2, - (size.height - textSize.height) / 2 - + g2d.getFontMetrics().getAscent()) - } - g2d.dispose(); - } - - def getTextSize(g2d: Graphics2D): Dimension = { - if (text == null) { - textSizeD.setSize(0, 0); - } else { - val frc: FontRenderContext = - if (g2d != null) { - g2d.getFontRenderContext() - } else { - new FontRenderContext(null, false, false) - } - val textRect: Rectangle2D = peer.getFont().getStringBounds( - text, - frc) - textSizeR.setRect(textRect) - textSizeD.setSize(textSizeR.width, textSizeR.height) - } - textSizeD; - } - - def getMinimumSize(): Dimension = { - if (userMinimumSize != null) { //user has set the min size - userMinimumSize; - } else { - getPreferredSize(); - } - } - - def getPreferredSize(): Dimension = { - if (userPreferredSize != null) { //user has set the pref size - userPreferredSize - } else { - calculatePreferredSize() - } - } - - def getMaximumSize(): Dimension = { - if (userMaximumSize != null) { //user has set the max size - userMaximumSize - } else { - new Dimension(Integer.MAX_VALUE, - Integer.MAX_VALUE) - } - } - - def setMinimumSize(newSize: Dimension) { - userMinimumSize = newSize - } - def setPreferredSize (newSize: Dimension) { - userPreferredSize = newSize; - } - def setMaximumSize (newSize: Dimension) { - userMaximumSize = newSize; - } - - private def calculatePreferredSize(): Dimension = { - val insets: Insets = peer.getInsets() - val textSize: Dimension = getTextSize(null) - var iconWidth = 0 - var iconHeight = 0 - - if (icon != null) { - iconWidth = icon.getIconWidth() - iconHeight = icon.getIconHeight() - } - - val d = new Dimension( - Math.max(iconWidth, textSize.width + 2 * xTextPad) - + insets.left + insets.right, - Math.max(iconHeight, textSize.height + 2 * yTextPad) - + insets.top + insets.bottom); - super.preferredSize = d - d - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala deleted file mode 100644 index 03ce3b83..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/SplitPaneDividerDemo.scala +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.ButtonClicked -import java.awt.Font - -/** - * How to Use Split Panes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SplitPaneDividerDemo.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/SplitPaneDividerDemoProject/src/components/SizeDisplayer.java]] - * - * SplitPaneDividerDemo.scala requires the following files: - * SizeDisplayer.scala - * /scala/swing/examples/tutorials/images/Cat.gif - * /scala/swing/examples/tutorials/images/Dog.gif - */ -class SplitPaneDividerDemo extends BorderPanel { - font = new Font("Serif", Font.ITALIC, 24) - val icon1 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Cat.gif") - val sd1 = new SizeDisplayer("left", icon1.orNull) { - font = font - } - sd1.setMinimumSize(new Dimension(30,30)) - - val icon2 = SplitPaneDividerDemo.createImageIcon("/scala/swing/examples/tutorials/images/Dog.gif") - val sd2 = new SizeDisplayer("right", icon2.orNull) { - font = font - } - sd2.setMinimumSize(new Dimension(30,30)) - - val splitPane = new SplitPane(Orientation.Vertical, sd1, sd2) { - resizeWeight = 0.5 - oneTouchExpandable = true - continuousLayout = true - } - - layout(splitPane) = BorderPanel.Position.Center - layout(createControlPanel) = BorderPanel.Position.South - - private def createControlPanel: Component = { - val panel = new FlowPanel() - val reset = new Button("Reset") - panel.contents += reset - - listenTo(reset) - reactions += { - case ButtonClicked(`reset`) => splitPane.resetToPreferredSizes() - } - panel - } -} - -object SplitPaneDividerDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } - - lazy val top = new MainFrame() { - title = "SplitPaneDividerDemo" - contents = new SplitPaneDividerDemo() - } -} - diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala deleted file mode 100644 index dd75fb76..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TabbedPaneDemo.scala +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components - -import scala.swing._ -import java.net.URL -import javax.swing.ImageIcon - -/** - * How to Use Split Panes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabbedPaneDemoProject/src/components/TabbedPaneDemo.java]] - * - * TabbedPaneDemo.scala requires one additional file: - * /scala/swing/examples/tutorials/images/middle.gif. - */ -class TabbedPaneDemo extends GridPanel(1, 1) { - val tabbedPane = new TabbedPane() - val icon1: ImageIcon = TabbedPaneDemo.createImageIcon("/scala/swing/examples/tutorials/images/middle.gif").get - val panel1: Panel = makeTextPanel("Panel #1") - tabbedPane.pages += new TabbedPane.Page("Tab 1", panel1, "Does nothing") - tabbedPane.pages(0).mnemonic = 1 - val panel2: Panel = makeTextPanel("Panel #2") - tabbedPane.pages += new TabbedPane.Page("Tab 2", panel2, "Does twice as much nothing") - tabbedPane.pages(1).mnemonic = 2 - val panel3: Panel = makeTextPanel("Panel #3") - tabbedPane.pages += new TabbedPane.Page("Tab 3", panel3, "Still does nothing") - tabbedPane.pages(2).mnemonic = 3 - val panel4: Panel = makeTextPanel("Panel #4 (has a preferred size of 410 x 50).") - panel4.preferredSize = new Dimension(410, 50) - tabbedPane.pages += new TabbedPane.Page("Tab 4", panel4, "Does nothing at all") - tabbedPane.pages(3).mnemonic = 4 - - //Add the tabbed pane to this panel. - contents += tabbedPane - - //The following line enables to use scrolling tabs. - tabbedPane.tabLayoutPolicy = TabbedPane.Layout.Scroll - - def makeTextPanel(text: String): Panel = { - val panel = new FlowPanel() - panel.peer.setDoubleBuffered(false) - val filler = new Label(text) { - horizontalAlignment = Alignment.Center - } - panel.contents += filler - panel - } -} - -object TabbedPaneDemo extends SimpleSwingApplication { - /** Returns an ImageIcon, or null if the path was invalid. */ - def createImageIcon(path: String): Option[javax.swing.ImageIcon] = { - Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - } - - lazy val top = new MainFrame() { - title = "TabbedPaneDemo" - contents = new TabbedPaneDemo() - } -} - diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala deleted file mode 100644 index 4f7eee5f..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableDemo.scala +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.MouseClicked -import javax.swing.table.DefaultTableModel - -/** - * Tutorial: How to Use Tables - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableDemoProject/src/components/TableDemo.java]] - * - * TableDemo.scala requires no other files. - * - * TableDemo is just like SimpleTableDemo, except that it uses a custom TableModel. - */ -class TableDemo extends GridPanel(1, 0) { - private val Debug = false - - val table = new Table(5, 5) { - model = new MyTableModel() - preferredViewportSize = new Dimension(500, 70) - } - table.peer.setFillsViewportHeight(true) - if (Debug) { - listenTo(table) - reactions += { - case e: MouseClicked => table.model.asInstanceOf[MyTableModel].printDebugData(table) - } - } - - //Create the scroll pane and add the table to it. - val scrollPane = new ScrollPane(table) - - //Add the scroll pane to this panel. - contents += scrollPane - class MyTableModel extends DefaultTableModel { - val columnNames: Array[String] = Array("First Name", - "Last Name", - "Sport", - "# of Years", - "Vegetarian") - val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) - data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) - data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) - data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) - data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) - - override def getColumnCount(): Int = { columnNames.length } - override def getRowCount(): Int = { if (data == null) 0 else data.length } - override def getColumnName(col: Int): String = { columnNames(col) } - override def getValueAt(row: Int, col: Int): Object = { - col match { - case 0 => data(row)(col).asInstanceOf[String] - case 1 => data(row)(col).asInstanceOf[String] - case 2 => data(row)(col).asInstanceOf[String] - case 3 => data(row)(col).asInstanceOf[java.lang.Integer] - case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] - } - } - /* - * Don't need to implement this method unless your table's - * data can change. - */ - override def setValueAt(value: Object, row: Int, col: Int): Unit = { - if (Debug) { - println("Setting value at " + row + "," + col + - " to " + value + - " (an instance of " + - value.getClass() + ")") - } - data(row)(col) = value - fireTableCellUpdated(row, col) - if (Debug) { - println("New value of data:") - printDebugData(table) - } - } - def printDebugData(table: Table): Unit = { - val numRows = table.rowCount - val numCols = table.peer.getColumnCount() - val model: javax.swing.table.TableModel = table.model - - println("Value of data: ") - for (i <- 0 until numRows) { - System.out.print(" row " + i + ":") - for (j <- 0 until numCols) { - print(" " + model.getValueAt(i, j)) - } - println() - } - println("--------------------------") - } - } -} - -object TableDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "TableDemo" - contents = new TableDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala deleted file mode 100644 index cb1ba4d5..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableFTFEditDemo.scala +++ /dev/null @@ -1,143 +0,0 @@ - -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import javax.swing.table.DefaultTableModel - -/** - * Tutorial: How to Use Tables - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/TableFTFEditDemo.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableFTFEditDemoProject/src/components/IntegerEditor.java]] - * - * TableFTFEditDemo.scala requires one other file: - * IntegerEditor.scala - * - * This is exactly like TableDemo, except that it uses a - * custom cell editor to validate integer input. - */ -class TableFTFEditDemo extends GridPanel(1, 0) { - private val Debug = false - val table = new Table(5, 5) { - model = new MyTableModel() - preferredViewportSize = new Dimension(500, 70) - } - table.peer.setFillsViewportHeight(true) - - //Create the scroll pane and add the table to it. - val scrollPane = new ScrollPane(table) - - //Set up stricter input validation for the integer column. - table.peer.setDefaultEditor(Class.forName("java.lang.Integer"), - new IntegerEditor(0, 100)); - - //If we didn't want this editor to be used for other - //Integer columns, we'd do this: - //table.getColumnModel().getColumn(3).setCellEditor( - // new IntegerEditor(0, 100)); - - //Add the scroll pane to this panel. - contents += scrollPane - class MyTableModel extends DefaultTableModel { - val columnNames: Array[String] = Array("First Name", - "Last Name", - "Sport", - "# of Years", - "Vegetarian") - val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) - data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) - data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) - data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) - data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) - - override def getColumnCount(): Int = { columnNames.length } - override def getRowCount(): Int = { if (data == null) 0 else data.length } - override def getColumnName(col: Int): String = { columnNames(col) } - override def getValueAt(row: Int, col: Int): Object = { - col match { - case 0 => data(row)(col).asInstanceOf[String] - case 1 => data(row)(col).asInstanceOf[String] - case 2 => data(row)(col).asInstanceOf[String] - case 3 => data(row)(col).asInstanceOf[java.lang.Integer] - case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] - } - } - - override def getColumnClass(c: Int): Class[_] = { - getValueAt(0, c).getClass(); - } - /* - * Don't need to implement this method unless your table's - * data can change. - */ - override def setValueAt(value: Object, row: Int, col: Int): Unit = { - if (Debug) { - println("Setting value at " + row + "," + col + - " to " + value + - " (an instance of " + - value.getClass() + ")") - } - data(row)(col) = value - fireTableCellUpdated(row, col) - if (Debug) { - println("New value of data:") - printDebugData(table) - } - } - def printDebugData(table: Table): Unit = { - val numRows = table.rowCount - val numCols = table.peer.getColumnCount() - val model: javax.swing.table.TableModel = table.model - - println("Value of data: ") - for (i <- 0 until numRows) { - System.out.print(" row " + i + ":") - for (j <- 0 until numCols) { - print(" " + model.getValueAt(i, j)) - } - println() - } - println("--------------------------") - } - } -} - -object TableFTFEditDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "TableFTFEditDemo" - contents = new TableFTFEditDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala deleted file mode 100644 index 93f4e9de..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TablePrintDemo.scala +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.ButtonClicked -import javax.swing.table.DefaultTableModel -import java.text.MessageFormat - -/** - * Tutorial: How to Use Tables - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TablePrintDemoProject/src/components/TablePrintDemo.java]] - * - * TablePrintDemo.scala requires no other files. - */ -class TablePrintDemo extends BoxPanel(Orientation.Vertical) { - private val Debug = false - - val table = new Table(5, 5) { - model = new MyTableModel() - preferredViewportSize = new Dimension(500, 70) - } - table.peer.setFillsViewportHeight(true) - // if (Debug) { - // listenTo(table) - // reactions += { - // case e: MouseClicked => printDebugData(table) - // } - // } - - //Create the scroll pane and add the table to it. - val scrollPane = new ScrollPane(table) - - //Add a print button. - val printButton = new Button("Print") { - // peer.setAlignmentX(0.5f) - xLayoutAlignment = java.awt.Component.CENTER_ALIGNMENT - } - - //Add the scroll pane to this panel. - contents += scrollPane - contents += printButton - - listenTo(printButton) - reactions += { - case ButtonClicked(`printButton`) => - val header: MessageFormat = new MessageFormat("Page {0, number, integer}") - try { - table.peer.print(javax.swing.JTable.PrintMode.FIT_WIDTH, header, null) - } catch { - case e: java.awt.print.PrinterException => - //sys.err does not have a print method - System.err.format("Cannot print %s%n", e.getMessage()) - } - } - - class MyTableModel extends DefaultTableModel { - val columnNames: Array[String] = Array("First Name", - "Last Name", - "Sport", - "# of Years", - "Vegetarian") - val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) - data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) - data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) - data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) - data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) - - override def getColumnCount(): Int = { columnNames.length } - override def getRowCount(): Int = { if (data == null) 0 else data.length } - override def getColumnName(col: Int): String = { columnNames(col) } - override def getValueAt(row: Int, col: Int): Object = { - col match { - case 0 => data(row)(col).asInstanceOf[String] - case 1 => data(row)(col).asInstanceOf[String] - case 2 => data(row)(col).asInstanceOf[String] - case 3 => data(row)(col).asInstanceOf[java.lang.Integer] - case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] - } - } - /* - * Don't need to implement this method unless your table's - * data can change. - */ - override def setValueAt(value: Object, row: Int, col: Int): Unit = { - if (Debug) { - println("Setting value at " + row + "," + col + - " to " + value + - " (an instance of " + - value.getClass() + ")") - } - data(row)(col) = value - fireTableCellUpdated(row, col) - if (Debug) { - println("New value of data:") - printDebugData(table) - } - } - def printDebugData(table: Table): Unit = { - val numRows = table.rowCount - val numCols = table.peer.getColumnCount() - val model: javax.swing.table.TableModel = table.model - - println("Value of data: ") - for (i <- 0 until numRows) { - System.out.print(" row " + i + ":") - for (j <- 0 until numCols) { - print(" " + model.getValueAt(i, j)) - } - println() - } - println("--------------------------") - } - } - -} - -object TablePrintDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "TablePrintDemo" - contents = new TablePrintDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala deleted file mode 100644 index 1687e1cd..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TableSelectionDemo.scala +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - - - -import scala.swing._ -import scala.swing.event.ButtonClicked -import javax.swing.event.{ListSelectionEvent, ListSelectionListener} -import javax.swing.table.DefaultTableModel - -/** - * Tutorial: How to Use Tables - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/table.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSelectionDemoProject/src/components/TableSelectionDemo.java]] - * - * TableSelectionDemo.scala requires no other files. - */ -class TableSelectionDemo extends BoxPanel(Orientation.Vertical) { - - val table = new Table(5, 5) { - model = new MyTableModel() - preferredViewportSize = new Dimension(500, 70) - } - table.peer.setFillsViewportHeight(true) - table.peer.getSelectionModel().addListSelectionListener(new RowListener()) - table.peer.getColumnModel().getSelectionModel(). - addListSelectionListener(new ColumnListener()); - //Create the scroll pane and add the table to it. - val scrollPane = new ScrollPane(table) - - contents += new Label("Selection Mode") - - val multipleInterval = new RadioButton("Multiple Interval Selection") { - selected = true - } - val single = new RadioButton("Single Selection") - val singleInterval = new RadioButton("Single Interval Selection") - val buttonGroup = new ButtonGroup() { - buttons += multipleInterval - buttons += single - buttons += singleInterval - } - contents += multipleInterval - contents += single - contents += singleInterval - - contents += new Label("Selection Options") - val rowCheck = new CheckBox("Row Selection") { - selected = true - } - val columnCheck = new CheckBox("Column Selection") - val cellCheck = new CheckBox("Cell Selection") { - enabled = false - } - contents += rowCheck - contents += columnCheck - contents += cellCheck - - //Add the scroll pane to this panel. - contents += scrollPane - - val output = new TextArea(5, 40) { - editable = false - } - - contents += new ScrollPane(output) - - listenTo(multipleInterval) - listenTo(single) - listenTo(singleInterval) - listenTo(rowCheck) - listenTo(columnCheck) - listenTo(cellCheck) - - reactions += { - case ButtonClicked(`rowCheck`) => - //Scala swing does not allow cell selection to be set independently. - if (rowCheck.selected) { - table.selection.elementMode = Table.ElementMode.Row - columnCheck.selected = false - cellCheck.selected = false - } - else { - table.selection.elementMode = Table.ElementMode.None - } - case ButtonClicked(`columnCheck`) => - //Scala swing does not allow cell selection to be set independently. - if (columnCheck.selected) { - table.selection.elementMode = Table.ElementMode.Column - rowCheck.selected = false - cellCheck.selected = false - } - else { - table.selection.elementMode = Table.ElementMode.None - } - case ButtonClicked(`cellCheck`) => - //Scala swing does not allow cell selection to be set independently. - if (cellCheck.selected) { - table.selection.elementMode = Table.ElementMode.Cell - rowCheck.selected = false - columnCheck.selected = false - } - else { - table.selection.elementMode = Table.ElementMode.None - } - case ButtonClicked(`multipleInterval`) => - table.selection.intervalMode = Table.IntervalMode.MultiInterval - //If cell selection is on, turn it off. - if (cellCheck.selected) { - cellCheck.selected = false - cellCheck.enabled = false - table.selection.elementMode = Table.ElementMode.None - } - case ButtonClicked(`singleInterval`) => - table.selection.intervalMode = Table.IntervalMode.SingleInterval - cellCheck.enabled = true - case ButtonClicked(`single`) => - table.selection.intervalMode = Table.IntervalMode.Single - cellCheck.enabled = true - } - - def outputSelection(): Unit = { - output.append("Lead: %d, %d. ".format( - table.peer.getSelectionModel().getLeadSelectionIndex(), - table.peer.getColumnModel().getSelectionModel(). - getLeadSelectionIndex())); - output.append("Rows:"); - for (c: Int <- table.selection.rows) { - output.append(" " + c.asInstanceOf[Int]) - } - output.append(". Columns:"); - for (c: Int <- table.selection.columns) { - output.append(" " + c.asInstanceOf[Int]) - } - output.append(".\n"); - } - - class RowListener extends ListSelectionListener { - def valueChanged(event: ListSelectionEvent): Unit = { - if (!event.getValueIsAdjusting()) { - output.append("ROW SELECTION EVENT. ") - outputSelection() - } - } - } - - class ColumnListener extends ListSelectionListener { - def valueChanged(event: ListSelectionEvent): Unit = { - if (!event.getValueIsAdjusting()) { - output.append("COLUMN SELECTION EVENT. ") - outputSelection() - } - } - } - - class MyTableModel extends DefaultTableModel { - val columnNames: Array[String] = Array("First Name", - "Last Name", - "Sport", - "# of Years", - "Vegetarian") - val data: Array[Array[Any]] = new Array[Array[Any]](5) - data(0) = Array("Kathy", "Smith", "Snowboarding", new Integer(5), false) - data(1) = Array("John", "Doe", "Rowing", new Integer(3), true) - data(2) = Array("Sue", "Black", "Knitting", new Integer(2), false) - data(3) = Array("Jane", "White", "Speed reading", new Integer(20), true) - data(4) = Array("Joe", "Brown", "Pool", new Integer(10), false) - - override def getColumnCount(): Int = { columnNames.length } - override def getRowCount(): Int = { if (data == null) 0 else data.length } - override def getColumnName(col: Int): String = { columnNames(col) } - override def getValueAt(row: Int, col: Int): Object = { - col match { - case 0 => data(row)(col).asInstanceOf[String] - case 1 => data(row)(col).asInstanceOf[String] - case 2 => data(row)(col).asInstanceOf[String] - case 3 => data(row)(col).asInstanceOf[java.lang.Integer] - case 4 => data(row)(col).asInstanceOf[java.lang.Boolean] - } - } - - override def getColumnClass(c: Int): Class[_] = { - getValueAt(0, c).getClass(); - } - - /* - * Don't need to implement this method unless your table's - * editable. - */ - override def isCellEditable(row: Int, col: Int): Boolean = { - //Note that the data/cell address is constant, - //no matter where the cell appears onscreen. - if (col < 2) { - false; - } else { - true; - } - } - - /* - * Don't need to implement this method unless your table's - * data can change. - */ - override def setValueAt(value: Object, row: Int, col: Int): Unit = { - data(row)(col) = value - fireTableCellUpdated(row, col) - } - } -} - -object TableSelectionDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "TableSelectionDemo" - contents = new TableSelectionDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala deleted file mode 100644 index 1e76925c..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextComponentDemo.scala +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.collection.mutable.HashMap -import scala.concurrent.{ future, Future } -import scala.swing._ -import scala.swing.event.{ActionEvent, CaretUpdate} -import java.awt.{ Color, Dimension, Event, Insets } -import java.awt.event.KeyEvent -import javax.swing.{ InputMap, KeyStroke, SwingUtilities, UIManager } -import javax.swing.event.{ DocumentEvent, DocumentListener, UndoableEditEvent, UndoableEditListener } -import javax.swing.text.{ AbstractDocument, BadLocationException, DefaultEditorKit, Document, SimpleAttributeSet, StyleConstants, StyledDocument, StyledEditorKit } -import javax.swing.undo.UndoManager - -/** - * Tutorials: How to Use Text Fields - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html]] - * How to Use Actions - * [[http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/DocumentSizeFilter.java]] - * - * TextComponentDemo.scala requires one additional file: - * DocumentSizeFilter.scala - */ -class TextComponentDemo extends MainFrame { - private val MaxCharacters = 300 - private val newline = "\n" - title = "TextComponentDemo" - val undo: UndoManager = new UndoManager() - - //Create the text pane and configure it. - val textPane: TextPane = new TextPane() - textPane.caret.position = 0 - textPane.peer.setMargin(new Insets(5, 5, 5, 5)) - val styledDoc: StyledDocument = textPane.styledDocument - val doc: AbstractDocument = styledDoc.asInstanceOf[AbstractDocument] - doc.setDocumentFilter(new DocumentSizeFilter(MaxCharacters)) - - val scrollPane = new ScrollPane(textPane) - scrollPane.preferredSize = new Dimension(200, 200) - - val undoAction = new UndoAction() - val redoAction = new RedoAction() - - //Create the text area for the status log and configure it. - val changeLog = new TextArea(5, 30) - changeLog.editable = false - val scrollPaneForLog = new ScrollPane(changeLog) - - //Create a split pane for the change log and the text area. - val splitPane = new SplitPane(Orientation.Horizontal, scrollPane, scrollPaneForLog) - splitPane.oneTouchExpandable = true - - //Create the status area - val caretListenerLabel = new CaretListenerLabel("Caret Status") - val statusPane = new GridPanel(1, 1) { - contents += caretListenerLabel - } - - contents = new BorderPanel() { - layout(splitPane) = BorderPanel.Position.Center - layout(statusPane) = BorderPanel.Position.South - } - - //Set up the menu bar. - val actions = createActionTable(textPane) - val editMenu: Menu = createEditMenu() - val styleMenu: Menu = createStyleMenu() - val mb: MenuBar = new MenuBar() { - contents += editMenu - contents += styleMenu - } - menuBar = mb - - //Add some key bindings. - addBindings() - - //Put the initial text into the text pane. - initDocument() - textPane.caret.position = 0 - - //Start watching for undoable edits and caret changes. - listenTo(textPane.caret) - doc.addUndoableEditListener(new MyUndoableEditListener()) - reactions += { - case CaretUpdate(textPane) => - caretListenerLabel.displaySelectionInfo(textPane.caret.dot, textPane.caret.mark) - } - doc.addDocumentListener(new MyDocumentListener()) - - class MyUndoableEditListener extends UndoableEditListener { - def undoableEditHappened(e: UndoableEditEvent) { - undo.addEdit(e.getEdit()) - undoAction.updateUndoState() - redoAction.updateRedoState() - } - } - - class MyDocumentListener extends DocumentListener { - def insertUpdate(e: DocumentEvent): Unit = { - displayEditInfo(e) - } - def removeUpdate(e: DocumentEvent): Unit = { - displayEditInfo(e) - } - def changedUpdate(e: DocumentEvent): Unit = { - displayEditInfo(e) - } - private def displayEditInfo(e: DocumentEvent): Unit = { - val document: Document = e.getDocument() - val changeLength = e.getLength() - changeLog.append(e.getType.toString() + ":" + - changeLength + " character" + - (if (changeLength == 1) { ". " } else { "s. " }) + - " Text length = " + document.getLength() + - "." + newline) - } - } - - def addBindings(): Unit = { - val inputMap: InputMap = textPane.peer.getInputMap - //Ctrl-b to go backward one character - val keyb: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK) - inputMap.put(keyb, DefaultEditorKit.backwardAction) - //Ctrl-f to go forward one character - val keyf: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK) - inputMap.put(keyf, DefaultEditorKit.forwardAction) - //Ctrl-p to go up one line - val keyp: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK) - inputMap.put(keyp, DefaultEditorKit.upAction) - //Ctrl-n to go down one line - val keyn: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK) - inputMap.put(keyn, DefaultEditorKit.downAction) - } - - def createEditMenu(): Menu = { - val menu: Menu = new Menu("Edit") { - val undoMenuItem = new MenuItem(undoAction) { - enabled = false - reactions += { - case scala.swing.event.ButtonClicked(_) => { - import scala.concurrent.ExecutionContext.Implicits._ - val fUndo: Future[Unit] = future { - Swing.onEDT { - val actionEvent = new ActionEvent(this) - undoAction.actionPerformed(actionEvent) - } - } - fUndo onComplete { - case _ => {} - } - } - } - } - contents += undoMenuItem - val redoMenuItem = new MenuItem(redoAction) { - enabled = false - reactions += { - case scala.swing.event.ButtonClicked(_) => { - import scala.concurrent.ExecutionContext.Implicits._ - val fRedo: Future[Unit] = future { - Swing.onEDT { - val actionEvent: ActionEvent = new ActionEvent(this) - redoAction.actionPerformed(actionEvent) - } - } - fRedo onComplete { - case _ => {} - } - } - } - } - - contents += redoMenuItem - contents += new Separator() - // - //These actions come from the default editor kit. - //Get the ones we want and stick them in the menu. - // cut-to-clipboard - val oldCutAction = getActionByName(DefaultEditorKit.cutAction).get - val miCut = new MenuItem(DefaultEditorKit.cutAction) - miCut.peer.setAction(oldCutAction) - contents += miCut - // copy-to-clipboard - val oldCopyAction = getActionByName(DefaultEditorKit.copyAction).get - val miCopy = new MenuItem(DefaultEditorKit.copyAction) - miCopy.peer.setAction(oldCopyAction) - contents += miCopy - // paste-from-clipboard - val oldPasteAction = getActionByName(DefaultEditorKit.pasteAction).get - val miPaste = new MenuItem(DefaultEditorKit.pasteAction) - miPaste.peer.setAction(oldPasteAction) - contents += miPaste - // - contents += new Separator() - // select-all - val oldSelectAllAction = getActionByName(DefaultEditorKit.selectAllAction).get - val miSelectAll = new MenuItem(DefaultEditorKit.selectAllAction) - miSelectAll.peer.setAction(oldSelectAllAction) - contents += miSelectAll - } - menu - } - - def createStyleMenu(): Menu = { - val menu: Menu = new Menu("Style") { - val boldAction = new StyledEditorKit.BoldAction() - val miBold = new MenuItem("Bold") - miBold.peer.setAction(boldAction) - contents += miBold - // - val italicAction = new StyledEditorKit.ItalicAction() - val miItalic = new MenuItem("Italic") - miItalic.peer.setAction(italicAction) - contents += miItalic - // - val underlineAction = new StyledEditorKit.UnderlineAction() - val miUnderline = new MenuItem("Underline") - miUnderline.peer.setAction(underlineAction) - contents += miUnderline - // - contents += new Separator() - // - val font12Action = new StyledEditorKit.FontSizeAction("12", 12) - val miFont12 = new MenuItem("12") - miFont12.peer.setAction(font12Action) - contents += miFont12 - // - val font14Action = new StyledEditorKit.FontSizeAction("14", 14) - val miFont14 = new MenuItem("14") - miFont14.peer.setAction(font14Action) - contents += miFont14 - // - val font18Action = new StyledEditorKit.FontSizeAction("18", 18) - val miFont18 = new MenuItem("18") - miFont18.peer.setAction(font18Action) - contents += miFont18 - // - contents += new Separator() - // - val fontSerifAction = new StyledEditorKit.FontFamilyAction("Serif", "Serif") - val miFontSerif = new MenuItem("Serif") - miFontSerif.peer.setAction(fontSerifAction) - contents += miFontSerif - // - val fontSansSerifAction = new StyledEditorKit.FontFamilyAction("SansSerif", "SansSerif") - val miFontSansSerif = new MenuItem("SansSerif") - miFontSansSerif.peer.setAction(fontSansSerifAction) - contents += miFontSansSerif - // - contents += new Separator() - // - val fgRedAction = new StyledEditorKit.ForegroundAction("Red", Color.red) - val miFgRed = new MenuItem("Red") - miFgRed.peer.setAction(fgRedAction) - contents += miFgRed - // - val fgGreenAction = new StyledEditorKit.ForegroundAction("Green", Color.green) - val miFgGreen = new MenuItem("Green") - miFgGreen.peer.setAction(fgGreenAction) - contents += miFgGreen - // - val fgBlueAction = new StyledEditorKit.ForegroundAction("Blue", Color.blue) - val miFgBlue = new MenuItem("Blue") - miFgBlue.peer.setAction(fgBlueAction) - contents += miFgBlue - // - val fgBlackAction = new StyledEditorKit.ForegroundAction("Black", Color.black) - val miFgBlack = new MenuItem("Black") - miFgBlack.peer.setAction(fgBlackAction) - contents += miFgBlack - } - menu - } - - def initDocument(): Unit = { - val initString: Array[String] = - Array("Use the mouse to place the caret.", - "Use the edit menu to cut, copy, paste, and select text.", - "Also to undo and redo changes.", - "Use the style menu to change the style of the text.", - "Use the arrow keys on the keyboard or these emacs key bindings to move the caret:", - "Ctrl-f, Ctrl-b, Ctrl-n, Ctrl-p.") - - val attrs: Array[SimpleAttributeSet] = initAttributes(initString.length); - for (i <- 0 until initString.length) { - doc.insertString(doc.getLength(), initString(i) + newline, attrs(i)); - } - } - - def initAttributes(length: Int): Array[SimpleAttributeSet] = { - //Hard-code some attributes. - val attrs = new Array[SimpleAttributeSet](length) - attrs(0) = new SimpleAttributeSet() - StyleConstants.setFontFamily(attrs(0), "SansSerif") - StyleConstants.setFontSize(attrs(0), 16) - attrs(1) = new SimpleAttributeSet(attrs(0)) - StyleConstants.setBold(attrs(1), true) - attrs(2) = new SimpleAttributeSet(attrs(0)) - StyleConstants.setItalic(attrs(2), true) - attrs(3) = new SimpleAttributeSet(attrs(0)) - StyleConstants.setFontSize(attrs(3), 20) - attrs(4) = new SimpleAttributeSet(attrs(0)) - StyleConstants.setFontSize(attrs(4), 12) - attrs(5) = new SimpleAttributeSet(attrs(0)) - StyleConstants.setForeground(attrs(5), Color.red) - attrs - } - - //The following two methods allow us to find an - //action provided by the editor kit by its name. - def createActionTable(textComponent: TextComponent): HashMap[String, javax.swing.Action] = { - val hm = new HashMap[String, javax.swing.Action]() - for (a <- textComponent.peer.getActions()) { - val s = a.getValue(javax.swing.Action.NAME).asInstanceOf[String] - hm.put(s, a) - } - hm - } - - def getActionByName(name: String): Option[javax.swing.Action] = { - actions.get(name) - } - - class UndoAction extends Action("Undo") { - enabled = false - def apply() = {} - def actionPerformed(e: scala.swing.event.ActionEvent): Unit = { - try { - undo.undo(); - } catch { - case ex: javax.swing.undo.CannotUndoException => - println("Unable to undo: " + ex) - ex.printStackTrace() - } - updateUndoState() - redoAction.updateRedoState() - } - - def updateUndoState(): Unit = { - if (undo.canUndo()) { - enabled = true - peer.putValue(javax.swing.Action.NAME, undo.getUndoPresentationName()) - } else { - enabled = false - peer.putValue(javax.swing.Action.NAME, "Undo") - } - } - } - - class RedoAction extends Action("Redo") { - enabled = false - def apply() = {} - def actionPerformed(e: ActionEvent): Unit = { - try { - undo.redo() - } catch { - case ex: javax.swing.undo.CannotUndoException => - println("Unable to undo: " + ex) - ex.printStackTrace() - } - updateRedoState(); - undoAction.updateUndoState() - } - - def updateRedoState(): Unit = { - if (undo.canRedo()) { - enabled = true - peer.putValue(javax.swing.Action.NAME, undo.getRedoPresentationName()) - } else { - enabled = false - peer.putValue(javax.swing.Action.NAME, "Redo") - } - } - } - - class CaretListenerLabel(label: String) extends Label(label) { - private val newline = "\n" - text = label - //This method can be invoked from any thread. It - //invokes the setText and modelToView methods, which - //must run on the event dispatch thread. We use - //invokeLater to schedule the code for execution - //on the event dispatch thread. - def displaySelectionInfo(dot: Int, mark: Int): Unit = { - SwingUtilities.invokeLater(new Runnable() { - def run(): Unit = { - if (dot == mark) { // no selection - try { - val caretCoords: Rectangle = textPane.peer.modelToView(dot) - //Convert it to view coordinates. - text = "caret: text position: " + dot + ", view location = [" + - caretCoords.x + ", " + caretCoords.y + "]" + newline - } catch { - case ble: BadLocationException => - text = "selection from: " + mark + " to " + dot + newline - } - } else if (dot < mark) { - text = "selection from: " + dot + " to " + mark + newline - } else { - text = "selection from: " + mark + " to " + dot + newline - } - } - }) - } - } - -} - -object TextComponentDemo extends SimpleSwingApplication { - UIManager.put("swing.boldMetal", false) - lazy val top = new TextComponentDemo() -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala deleted file mode 100644 index 14649ae5..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextDemo.scala +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event.EditDone - -/** - * Tutorials: How to Use Text Fields - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html]] - * How to Use Text Areas - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/textarea.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextDemoProject/src/components/TextDemo.java]] - * - * TextDemo.scala requires no other files. - */ -class TextDemo extends GridBagPanel { - private val newline = "\n" - val textField = new TextField(20) - val textArea = new TextArea(5, 20) { - editable = false - } - val scrollPane = new ScrollPane(textArea) - - //Add Components to this panel. - val c: Constraints = new Constraints() - - c.gridwidth = java.awt.GridBagConstraints.REMAINDER - c.fill = GridBagPanel.Fill.Horizontal - layout(textField) = c - c.fill = GridBagPanel.Fill.Both - c.weightx = 1.0 - c.weighty = 1.0 - layout(scrollPane) = c - - listenTo(textField) - reactions += { - case EditDone(`textField`) => - textArea.text += textField.text + newline - textField.selectAll() - //Make sure the new text is visible, even if there - //was a selection in the text area. - textArea.caret.position = textArea.peer.getDocument().getLength() - } -} - -object TextDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "TextDemo" - contents = new TextDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala deleted file mode 100644 index e9d2cb06..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TextSamplerDemo.scala +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package scala.swing.examples.tutorials.components - -import scala.swing._ -import scala.swing.event._ -import java.awt.{ Cursor, Font, Toolkit } -import java.net.URL -import javax.swing.text.{ StyleConstants, StyleContext } - -/** - * Tutorials: How to Use Text Components - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/text.html]] - * How to Use Editor Panes and Text Panes - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html]] - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextSamplerDemoProject/src/components/TextSamplerDemo.java]] - * - * TextSamplerDemo.scala requires the following files: - * TextSamplerDemoHelp.html (which references images/dukeWaveRed.gif) - * /scala/swing/examples/tutorials/images/Pig.gif - * /scala/swing/examples/tutorials/images/sound.gif - */ -object TextSamplerDemo extends SimpleSwingApplication { - val newline = "\n" - - lazy val top = new MainFrame() { - title = "TextSamplerDemo" - - private val textFieldString = "TextField" - private val passwordFieldString = "PasswordField" - private val ftfString = "FormattedTextField" - private val buttonString = "Button" - - val button = new Button() - - //Create a regular text field. - val textField = new TextField(10) - - //Create a password field. - val passwordField = new PasswordField(10) - - //Create a formatted text field. - val ftf = new FormattedTextField(java.text.DateFormat.getDateInstance()) - // Had to use the peer for this purpose.......................................... - ftf.peer.setValue(java.util.Calendar.getInstance().getTime()) - - //Create some labels for the fields. - val textFieldLabel = new Label(textFieldString + ": ") - // textFieldLabel.setLabelFor(textField) - val passwordFieldLabel = new Label(passwordFieldString + ": ") - val ftfLabel = new Label(ftfString + ": ") - // ftfLabel.setLabelFor(ftf) - - //Create a label to put messages during an action event. - val actionLabel = new Label("Type text in a field and press Enter.") - actionLabel.border = Swing.EmptyBorder(10, 0, 0, 0) - - //Lay out the text controls and the labels. - val textControlsPane = new GridBagPanel { - val c: Constraints = new Constraints() - - c.gridwidth = java.awt.GridBagConstraints.RELATIVE - c.fill = GridBagPanel.Fill.None - c.weightx = 0.0 - layout(textFieldLabel) = c - - c.gridwidth = java.awt.GridBagConstraints.REMAINDER - c.fill = GridBagPanel.Fill.Horizontal - c.weightx = 1.0 - layout(textField) = c - - c.gridwidth = java.awt.GridBagConstraints.RELATIVE - c.fill = GridBagPanel.Fill.None - c.weightx = 0.0 - layout(passwordFieldLabel) = c - - c.gridwidth = java.awt.GridBagConstraints.REMAINDER - c.fill = GridBagPanel.Fill.Horizontal - c.weightx = 1.0 - layout(passwordField) = c - - c.gridwidth = java.awt.GridBagConstraints.RELATIVE - c.fill = GridBagPanel.Fill.None - c.weightx = 0.0 - layout(ftfLabel) = c - - c.gridwidth = java.awt.GridBagConstraints.REMAINDER - c.fill = GridBagPanel.Fill.Horizontal - c.weightx = 1.0 - layout(ftf) = c - - c.gridwidth = java.awt.GridBagConstraints.REMAINDER // last - c.anchor = GridBagPanel.Anchor.West - c.weightx = 1.0 - layout(actionLabel) = c - - border = Swing.CompoundBorder( - Swing.TitledBorder(Swing.EmptyBorder, "Text Fields"), - Swing.EmptyBorder(5, 5, 5, 5)) - } - - //Create a text area. - val textArea = new TextArea( - "This is an editable TextArea. " + - "A text area is a \"plain\" text component, " + - "which means that although it can display text " + - "in any font, all of the text is in the same font.") - textArea.font = new Font("Serif", Font.ITALIC, 16) - textArea.lineWrap = true - textArea.wordWrap = true - - //Put the text area in a scrollpane - val areaScrollPane: ScrollPane = new ScrollPane(textArea) - areaScrollPane.verticalScrollBarPolicy = ScrollPane.BarPolicy.Always - areaScrollPane.preferredSize = new Dimension(250, 250) - areaScrollPane.border = - Swing.CompoundBorder( - Swing.CompoundBorder( - Swing.TitledBorder(Swing.EmptyBorder, "Plain Text"), - Swing.EmptyBorder(5, 5, 5, 5)), areaScrollPane.border) - - //Create an editor pane. - val editorPane: EditorPane = new EditorPane() - editorPane.editable = false - //To get this to work in Eclipse, add /src/main/resources directory to the run - //configuration classpath. The file TextSamplerDemoHelp.html is placed in that - //directory. - val helpURL: URL = getClass().getResource("/scala/swing/examples/tutorials/TextSamplerDemoHelp.html") - - if (helpURL != null) { - editorPane.editorKit = new javax.swing.text.html.HTMLEditorKit - editorPane.contentType = "text/html" - // Had to reach into the peer for this................... - editorPane.peer.setPage(helpURL) - } else { - textField.text = "TextSampleDemoHelp.html was not found." - } - - val editorScrollPane = new ScrollPane(editorPane) - editorScrollPane.verticalScrollBarPolicy = ScrollPane.BarPolicy.Always - editorScrollPane.preferredSize = new java.awt.Dimension(250, 145) - editorScrollPane.minimumSize = new java.awt.Dimension(10, 10) - - //Create a text pane and put it into a scrollpane. - // val textPane:TextPane = new TextPane() - val textPane: TextPane = createTextPane(button) - - val paneScrollPane = new ScrollPane(textPane) - - paneScrollPane.verticalScrollBarPolicy = ScrollPane.BarPolicy.Always - paneScrollPane.preferredSize = new java.awt.Dimension(250, 155) - paneScrollPane.minimumSize = new java.awt.Dimension(10, 10) - - //Put the editor pane and the text pane in a split pane. - //Use Orientation.Horizontal instead of JSplitPane.VERTICAL_SPLIT - val splitPane = new SplitPane(Orientation.Horizontal, - editorScrollPane, paneScrollPane) - splitPane.oneTouchExpandable = true - splitPane.resizeWeight = 0.5 - - //Place the splitpane in a panel destined for the right of the screen - val rightPane = new GridPanel(1, 0) { - contents += splitPane - border = Swing.CompoundBorder( - Swing.TitledBorder(Swing.EmptyBorder, "Styled Text"), - Swing.EmptyBorder(5, 5, 5, 5)) - } - - //Place the text and area controls in a panel destined for the left - // of the screen - val leftPane = new BorderPanel() { - layout(textControlsPane) = BorderPanel.Position.North - layout(areaScrollPane) = BorderPanel.Position.Center - } - - listenTo(textField) - listenTo(passwordField) - listenTo(button) - val prefix = "You typed \"" - reactions += { - case EditDone(`textField`) => - actionLabel.text = prefix + textField.text + "\"" - case EditDone(`passwordField`) => - actionLabel.text = prefix + passwordField.password + "\"" - case ButtonClicked(`button`) => - Toolkit.getDefaultToolkit().beep() // No sound heard... - actionLabel.text = "Beep?!" - } - - contents = new BorderPanel() { - layout(leftPane) = BorderPanel.Position.West - layout(rightPane) = BorderPanel.Position.East - } - } - - def addStylesToDocument(doc: javax.swing.text.StyledDocument, button: Button): Unit = { - val `def` = StyleContext.getDefaultStyleContext.getStyle(StyleContext.DEFAULT_STYLE) - val regular = doc.addStyle("regular", `def`) - StyleConstants.setFontFamily(`def`, "SansSerif") - val sItalic = doc.addStyle("italic", regular) - StyleConstants.setItalic(sItalic, true) - val sBold = doc.addStyle("bold", regular) - StyleConstants.setBold(sBold, true) - val sSmall = doc.addStyle("small", regular) - StyleConstants.setFontSize(sSmall, 10) - val sLarge = doc.addStyle("large", regular) - StyleConstants.setFontSize(sLarge, 16) - val sIcon = doc.addStyle("icon", regular) - StyleConstants.setAlignment(sIcon, StyleConstants.ALIGN_CENTER) - val pigIcon = createImageIcon("/scala/swing/examples/tutorials/images/Pig.gif", "a cute pig") - if (pigIcon != None) { - StyleConstants.setIcon(sIcon, pigIcon.get) - } - val sButton = doc.addStyle("button", regular) - StyleConstants.setAlignment(sButton, StyleConstants.ALIGN_CENTER) - val soundIcon = createImageIcon("/scala/swing/examples/tutorials/images/sound.gif", "sound icon") - // button = new Button() - if (soundIcon != None) { - button.icon = soundIcon.get - } else { - button.text = "BEEP" - } - button.cursor = Cursor.getDefaultCursor - button.margin = new Insets(0, 0, 0, 0) - // button.setActionCommand(buttonString) - // button.addActionListener(this) - StyleConstants.setComponent(sButton, button.peer) - } - - def createTextPane(button: Button): TextPane = { - val initStrings: Array[String] = Array( - "This is an editable TextPane, ", //regular - "another ", //italic - "styled ", //bold - "text ", //small - "component, ", //large - "which supports embedded components..." + newline, //regular - " " + newline, //button - "...and embedded icons..." + newline, //regular - " ", //icon - newline + "Its peer, JTextPane, is a subclass of JEditorPane that " + - "uses a StyledEditorKit and StyledDocument, and provides " + - "cover methods for interacting with those objects.") - val initStyles: Array[String] = Array( - "regular", "italic", "bold", "small", "large", - "regular", "button", "regular", "icon", - "regular") - val textPane = new TextPane() - val doc: javax.swing.text.StyledDocument = textPane.styledDocument - addStylesToDocument(doc, button) - for (i <- 0 until initStrings.length) { - doc.insertString(doc.getLength(), initStrings(i), doc.getStyle(initStyles(i))) - } - textPane - } - - private def createImageIcon(path: String, description: String): Option[javax.swing.ImageIcon] = { - val icon = Option(resourceFromClassloader(path)).map(imgURL => Swing.Icon(imgURL)) - if (icon.isDefined) { icon.get.setDescription(description); icon } else None - } -} - - - - diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala b/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala deleted file mode 100644 index df7a3b06..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/components/TumbleItem.scala +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.components - -import scala.swing._ -import java.io.BufferedInputStream -import java.awt.event.{ ActionEvent, ActionListener } -import java.awt.{ Color, Graphics, Graphics2D, Toolkit } -import javax.swing.{ ImageIcon, SwingUtilities, SwingWorker, Timer } - -/** - * Tutorial: How to Make Applets - * [[http://docs.oracle.com/javase/tutorial/uiswing/components/applet.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TumbleItemProject/src/components/TumbleItem.java]] - * - * @author jag - * @author mem - * @author kwalrath - * @author ir71389 - * - * TumbleItem.scala requires these files: - * all the images in the /scala/swing/examples/tutorials/images/tumble directory - * (or, if specified in the applet tag, another directory [dir] - * with images named T1.gif ... Tx.gif, where x is the total - * number of images [nimgs]) - * the appropriate code to specify that the applet be executed, - * such as the HTML code in TumbleItem.html or TumbleItem.atag, - * or the JNLP code in TumbleItem.jnlp - * - */ -class TumbleItem extends Applet { - var loopslot = -1 //the current frame number - var timer: Timer = null //the timer animating the images - var dir: String = null //the directory relative to the codebase - //from which the images are loaded - var pause: Int = 0 //the length of the pause between revs - var offset: Int = 0 //how much to offset between loops - var speed: Int = 0 //animation speed - var nimgs: Int = 0 //number of images to animate - var maxWidth: Int = 0 //width of widest image - var mywidth: Int = 0 //width of the applet's content pane - var off: Int = 0 //the current offset - var imgs: Array[ImageIcon] = null - var worker: SwingWorker[Array[ImageIcon], Void] = null - val ui = new ui() - - def loadAppletParameters(): Unit = { - //Get the applet parameters. - var at: String = getParameter("img") - dir = if (at != null) at else "/scala/swing/examples/tutorials/images/tumble" - at = getParameter("pause") - pause = if (at != null) Integer.valueOf(at).intValue() else 1900 - at = getParameter("offset") - offset = if (at != null) Integer.valueOf(at).intValue() else 0 - at = getParameter("speed") - speed = if (at != null) (1000 / Integer.valueOf(at).intValue()) else 100 - at = getParameter("nimgs"); - nimgs = if (at != null) Integer.valueOf(at).intValue() else 16 - at = getParameter("maxwidth"); - maxWidth = if (at != null) Integer.valueOf(at).intValue() else 0 - imgs = new Array[ImageIcon](nimgs) - } - - class ui extends UI with ActionListener { - /** - * Create the GUI. For thread safety, this method should - * be invoked from the event-dispatching thread. - */ - private def createGUI(): Unit = { - //Animate from right to left if offset is negative. - mywidth = getSize().width - if (offset < 0) { - off = mywidth - maxWidth; - } - - //Custom component to draw the current image - //at a particular offset. - animator = new Animator() - animator.opaque = true - animator.background = Color.white - setContentPane(animator.peer) - - //Put a "Loading Images..." label in the middle of - //the content pane. To center the label's text in - //the applet, put it in the center part of a - //BorderLayout-controlled container, and center-align - //the label's text. - val statusLabel = new Label("Loading Images...", - Swing.EmptyIcon, Alignment.Center) - animator.layout(statusLabel) = BorderPanel.Position.Center - } - - var animator: Animator = null //the applet's content pane - //Background task for loading images. - worker = new SwingWorker[Array[ImageIcon], Void]() { - override def doInBackground(): Array[ImageIcon] = { - val innerImgs: Array[ImageIcon] = new Array[ImageIcon](nimgs) - for (i <- 0 until nimgs) { - innerImgs(i) = loadImage(i + 1) - } - innerImgs; - } - - override def done(): Unit = { - //Remove the "Loading images" label. - animator.clear() - loopslot = -1 - try { - imgs = get() - } catch { - case ignore: java.lang.InterruptedException => {} - case e: java.util.concurrent.ExecutionException => - val cause: Throwable = e.getCause() - val why = if (cause != null) - cause.getMessage() - else - e.getMessage() - System.err.println("Error retrieving file: " + why) - } - } - } - - //Called when this applet is loaded into the browser. - override def init(): Unit = { - loadAppletParameters() - - //Execute a job on the event-dispatching thread: - //creating this applet's GUI. - try { - SwingUtilities.invokeAndWait(new Runnable() { - def run(): Unit = { - createGUI(); - } - }); - } catch { - case e: Exception => - System.err.println("createGUI didn't successfully complete") - } - - //Set up timer to drive animation events. - timer = new Timer(speed, this); - timer.setInitialDelay(pause); - timer.start(); - - //Start loading the images in the background. - worker.execute(); - - } - - override def start(): Unit = { - if (worker.isDone() && (nimgs > 1)) { - timer.restart - } - } - - override def stop(): Unit = { - timer.stop - } - - //The component that actually presents the GUI. - class Animator extends BorderPanel { - - protected def paintComponent(g: Graphics): Unit = { - super.paintComponent(g.asInstanceOf[Graphics2D]); - - if (worker.isDone() && - (loopslot > -1) && (loopslot < nimgs)) { - if (imgs != null && imgs(loopslot) != null) { - imgs(loopslot).paintIcon(peer, g, off, 0); - } - } - } - - def clear(): Unit = { - removeAll() - } - - } - - //Handle timer event. Update the loopslot (frame number) and the - //offset. If it's the last frame, restart the timer to get a long - //pause between loops. - def actionPerformed(e: ActionEvent): Unit = { - //If still loading, can't animate. - if (worker.isDone()) { - loopslot += 1 - - if (loopslot >= nimgs) { - loopslot = 0 - off += offset - - if (off < 0) { - off = mywidth - maxWidth - } else if (off + maxWidth > mywidth) { - off = 0; - } - } - animator.repaint() - if (loopslot == nimgs - 1) { - timer.restart() - } - } - } - } - - /** - * Load the image for the specified frame of animation. Since - * this runs as an applet, we use getResourceAsStream for - * efficiency and so it'll work in older versions of Java Plug-in. - */ - def loadImage(imageNum: Int): ImageIcon = { - val path = dir + "/T" + imageNum + ".gif" - val MAX_IMAGE_SIZE = 2400 //Change this to the size of - //your biggest image, in bytes. - var count = 0 - val imgStream = new BufferedInputStream(this.getClass().getResourceAsStream(path)) - if (imgStream != null) { - val buf = new Array[Byte](MAX_IMAGE_SIZE) - var ex = false - try { - count = imgStream.read(buf); - imgStream.close(); - } catch { - case ioe: java.io.IOException => - System.err.println("Couldn't read stream from file: " + path) - count = -1 - } - if (count <= 0) { - System.err.println("Empty file: " + path); - null - } else - new ImageIcon(Toolkit.getDefaultToolkit().createImage(buf)); - } else { - System.err.println("Couldn't find file: " + path); - null - } - } - - override def getAppletInfo(): String = { - "Title: TumbleItem v1.2, 23 Jul 1997\n" + - "Author: James Gosling\n" + - "A simple Item class to play an image loop." - } - - override def getParameterInfo(): Array[Array[String]] = { - val info = new Array[Array[String]](6) - info(0) = Array("img", "string", "the directory containing the images to loop") - info(1) = Array("pause", "int", "pause between complete loops; default is 3900") - info(2) = Array("offset", "int", "offset of each image to simulate left (-) or " + - "right (+) motion; default is 0 (no motion)") - info(3) = Array("speed", "int", "the speed at which the frames are looped; " + - "default is 100") - info(4) = Array("nimgs", "int", "the number of images to be looped; default is 16") - info(5) = Array("maxwidth", "int", "the maximum width of any image in the loop; " + - "default is 0") - info - } - -} diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala deleted file mode 100644 index f93fe1c4..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/events/ListSelectionDemo.scala +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.events - -import scala.swing._ -import scala.swing.event.{ButtonClicked, SelectionChanged} -import java.awt.Dimension - -/** - * Tutorial: How to Write a List Selection Listener - * [[http://docs.oracle.com/javase/tutorial/uiswing/events/listselectionlistener.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/events/ListSelectionDemoProject/src/events/ListSelectionDemo.java]] - * - * ListSelectionDemo.scala requires no other files. - */ -class ListSelectionDemo extends BorderPanel { - val listData = Array( "one", "two", "three", "four", - "five", "six", "seven" ) - val columnNames = Array( "French", "Spanish", "Italian" ) - val list = new ListView(listData) - val listPane = new ScrollPane(list) - - val modes = Array( "SINGLE_SELECTION", "SINGLE_INTERVAL_SELECTION", - "MULTIPLE_INTERVAL_SELECTION") - val comboBox = new ComboBox(modes) { - selection.index = 2 - } - val controlPane = new FlowPanel() { - contents += new Label("Selection mode:") - contents += comboBox - } - - //Build output area. - val output = new TextArea(1, 10) { - editable = false - } - val outputPane = new ScrollPane(output) { - verticalScrollBarPolicy = ScrollPane.BarPolicy.Always - horizontalScrollBarPolicy = ScrollPane.BarPolicy.AsNeeded - } - val listContainer = new GridPanel(1, 1) { - contents += listPane - border = Swing.TitledBorder(Swing.EmptyBorder, "List") - } - val topHalf = new BoxPanel(Orientation.Horizontal) { - contents += listContainer - border = Swing.EmptyBorder(5, 5, 0, 5) - minimumSize = new Dimension(100, 50) - preferredSize = new Dimension(100, 110) - } - - val bottomHalf = new BorderPanel() { - layout(controlPane) = BorderPanel.Position.North - layout(outputPane) = BorderPanel.Position.Center - preferredSize = new Dimension(450, 135) - } - - //Do the layout. - val splitPane = new SplitPane(Orientation.Horizontal, topHalf, bottomHalf) - - layout(splitPane) = BorderPanel.Position.Center - - listenTo(comboBox.selection) - listenTo(list.selection) - - reactions += { - case SelectionChanged(`comboBox`) => - val newMode = comboBox.selection.item - newMode match { - case "SINGLE_SELECTION" => - list.selection.intervalMode = ListView.IntervalMode.Single - case "SINGLE_INTERVAL_SELECTION" => - list.selection.intervalMode = ListView.IntervalMode.SingleInterval - case "MULTIPLE_INTERVAL_SELECTION" => - list.selection.intervalMode = ListView.IntervalMode.MultiInterval - } - output.append("----------" + "Mode: " + newMode + "----------" + "\n") - case SelectionChanged(`list`) => - val firstIndex = list.selection.leadIndex - val lastIndex = list.selection.anchorIndex // anchor = last? - val isAdjusting = list.selection.adjusting - output.append("Event for indexes " + firstIndex + " - " + lastIndex + - "; isAdjusting is " + isAdjusting + "; selected indexes:") - if (list.selection.indices.isEmpty) { - output.append(" ") - } - else { - // Find out which indexes are selected. - for (i <- list.selection.indices) { - output.append(" " + i) - } - } - output.append("\n") - output.caret.position = output.peer.getDocument().getLength() - } -} - -object ListSelection extends SimpleSwingApplication { - //Create and set up the window. - lazy val top = new MainFrame { - title = "ListSelectionDemo" - contents = new ListSelectionDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala deleted file mode 100644 index a2ad0c93..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/BorderLayoutDemo.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.layout - -import scala.swing._ -import javax.swing.{SwingUtilities, UIManager} -import java.awt.{ ComponentOrientation, Dimension } - -/** - * Tutorials: How to Use BorderLayout - * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/BorderLayoutDemoProject/src/layout/BorderLayoutDemo.java]] - */ -class BorderLayoutDemo extends BorderPanel { - if (BorderLayoutDemo.RightToLeft) { - peer.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) - } - val button1 = new Button("Button 1 (PAGE_START)") - val button2 = new Button("Button 2 (CENTER)") { - preferredSize = new Dimension(200, 100) - } - val button3 = new Button("Button 3 (LINE_START)") - val button4 = new Button("Long-Named Button 4 (PAGE_END)") - val button5 = new Button("5 (LINE_START)") - - layout(button1) = BorderPanel.Position.North - layout(button2) = BorderPanel.Position.Center - layout(button3) = BorderPanel.Position.West - layout(button4) = BorderPanel.Position.East - layout(button5) = BorderPanel.Position.South -} - -object BorderLayoutDemo extends SimpleSwingApplication { - val RightToLeft = false - /* Use an appropriate Look and Feel */ - UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") - /* Turn off metal's use bold fonts */ - UIManager.put("swing.boldMetal", false) - //Create and set up the window. - lazy val top = new MainFrame { - title = "BorderLayoutDemo" - contents = new BorderLayoutDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala deleted file mode 100644 index 0a4bea9f..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/CustomLayoutDemo.scala +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.layout - -import scala.swing._ - -/** - * Tutorials: Creating a Custom Layout Manager - * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/custom.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/CustomLayoutDemo.java]] - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/CustomLayoutDemoProject/src/layout/DiagonalLayout.java]] - * - * CustomLayoutDemo.scala requires one other file: - * DiagonalLayout.scala - */ -class CustomLayoutDemo() extends Panel with SequentialContainer.Wrapper { - override lazy val peer: javax.swing.JPanel = - new javax.swing.JPanel(new DiagonalLayout()) with SuperMixin - - private def layoutManager = peer.getLayout.asInstanceOf[DiagonalLayout] - - val b1 = new Button("Button 1") - val b2 = new Button("Button 2") - val b3 = new Button("Button 3") - val b4 = new Button("Button 4") - val b5 = new Button("Button 5") - val buttons: Seq[Component] = Seq(b1, b2, b3, b4, b5) - contents ++= buttons -} - -object CustomLayoutDemo extends SimpleSwingApplication { - lazy val top = new MainFrame() { - title = "CustomLayoutDemo" - contents = new CustomLayoutDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala deleted file mode 100644 index 325fba53..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/FlowLayoutDemo.scala +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.layout - -import scala.swing._ -import scala.swing.event.ButtonClicked -import java.awt.ComponentOrientation -import javax.swing.UIManager - -/** - * Tutorials: How to Use FlowLayout - * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/flow.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/FlowLayoutDemoProject/src/layout/FlowLayoutDemo.java]] - * - * FlowLayoutDemo.scala requires no other files - */ -class FlowLayoutDemo extends BorderPanel { - val RtoL = "Right to left" - val LtoR = "Left to right" - val controls: FlowPanel = new FlowPanel() - val applyButton = new Button("Apply component orientation") - val compsToExperiment = new FlowPanel(FlowPanel.Alignment.Trailing)() - val LtoRbutton = new RadioButton(LtoR) { selected = true } - val RtoLbutton = new RadioButton(RtoL) - - //Add buttons to the experiment layout - compsToExperiment.contents += new Button("Button 1") - compsToExperiment.contents += new Button("Button 2") - compsToExperiment.contents += new Button("Button 3") - compsToExperiment.contents += new Button("Long Named Button 4") - compsToExperiment.contents += new Button("5") - - //Left to right component orientation is selected by default - compsToExperiment.peer.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT) - - //Add controls to set up the component orientation in the experiment layout - val group = new ButtonGroup() { - buttons += LtoRbutton - buttons += RtoLbutton - } - controls.contents += LtoRbutton - controls.contents += RtoLbutton - controls.contents += applyButton - - layout(compsToExperiment) = BorderPanel.Position.Center - layout(controls) = BorderPanel.Position.South - - listenTo(applyButton) - reactions += { - case ButtonClicked(`applyButton`) => - if (LtoRbutton.selected) { - compsToExperiment.peer.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT) - } - else { - compsToExperiment.peer.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT) - } - compsToExperiment.peer.validate() - compsToExperiment.repaint() - } -} - -object FlowLayoutDemo extends SimpleSwingApplication { - /* Use an appropriate Look and Feel */ - UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") - /* Turn off metal's use of bold fonts */ - UIManager.put("swing.boldMetal", false) - lazy val top = new MainFrame() { - title = "FlowLayoutDemo" - contents = new FlowLayoutDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala deleted file mode 100644 index 766c7735..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/layout/GridLayoutDemo.scala +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.layout - -import scala.swing._ -import scala.swing.event.ButtonClicked -import javax.swing.UIManager -import java.awt.Dimension - -/** - * Tutorials: How to Use GridLayout - * [[http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html]] - * - * Source code reference: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/layout/GridLayoutDemoProject/src/layout/GridLayoutDemo.java]] - */ -class GridLayoutDemo extends BorderPanel { - private val gapList = Array("0", "10", "15", "20") - private val maxGap = 20 - val horGapComboBox = new ComboBox(gapList) - val verGapComboBox = new ComboBox(gapList) - val applyButton = new Button("Apply gaps") - val compsToExperiment = new GridPanel(0, 2) - val controls = new GridPanel(2, 3) - //Set up components preferred size - val b = new Button("Just fake button") - val buttonSize = b.preferredSize - compsToExperiment.preferredSize = - new Dimension((buttonSize.getWidth() * 2.5).toInt + maxGap, - (buttonSize.getHeight() * 3.5).toInt + maxGap * 2) - - //Add buttons to experiment with Grid Layout - compsToExperiment.contents += new Label("Horizontal gap:") - compsToExperiment.contents += new Label("Vertical gap:") - compsToExperiment.contents += new Label(" ") - compsToExperiment.contents += horGapComboBox - compsToExperiment.contents += verGapComboBox - compsToExperiment.contents += applyButton - layout(compsToExperiment) = BorderPanel.Position.North - layout(controls) = BorderPanel.Position.South - - listenTo(applyButton) - reactions += { - case ButtonClicked(`applyButton`) => - //Get the horizontal gap value - val horGap = horGapComboBox.selection.item - //Get the vertical gap value - val verGap = verGapComboBox.selection.item - //Set up the horizontal gap value - compsToExperiment.hGap = horGap.toInt - //Set up the vertical gap value - compsToExperiment.vGap = verGap.toInt - //Set up the layout of the buttons - compsToExperiment.peer.getLayout().layoutContainer(compsToExperiment.peer) - } -} - -object GridLayoutDemo extends SimpleSwingApplication { - /* Use an appropriate Look and Feel */ - UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") - /* Turn off metal's use bold fonts */ - UIManager.put("swing.boldMetal", false) - //Create and set up the window. - lazy val top = new MainFrame { - title = "GridLayoutDemo" - resizable = false - contents = new GridLayoutDemo() - } -} \ No newline at end of file diff --git a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala b/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala deleted file mode 100644 index 094b8428..00000000 --- a/examples/src/main/scala/scala/swing/examples/tutorials/misc/ActionDemo.scala +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle or the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package scala.swing.examples.tutorials.misc - -import scala.swing._ -import scala.swing.event.{ ActionEvent, ButtonClicked, KeyEvent } -import java.awt.Dimension -//import java.awt.event.{ ActionEvent, ActionListener, KeyEvent } -import java.net.URL -import javax.swing.{ ImageIcon, JToolBar } - -/** - * Tutorials: How to Use Actions - * [[http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html]] - * - * The graphics in this application require a download of the Java Look and Feel Graphics - * Repository from Oracle. - * [[http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-client-419417.html#7520-jlf-1.0-oth-JPR]] - * Accept the user agreement from the site, unzip, and place the jar file contents in your classpath. - * - * Source code references: - * [[http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/ActionDemoProject/src/misc/ActionDemo.java]] - * - * ActionDemo.scala requires the Java Look and Feel jar file jlfgr-1_0.jar. - */ -class ActionDemo extends BorderPanel { - //Create a scrolled text area. - val textArea = new TextArea(5, 30) { - editable = false - } - val scrollPane = new ScrollPane(textArea) - preferredSize = new Dimension(450, 150) - - layout(scrollPane) = BorderPanel.Position.Center - - //Create the actions shared by the toolbar and menu. - val leftAction = new LeftAction() - class LeftAction extends Action("Go left") { - override def apply(): Unit = {} - icon = ActionDemo.createNavigationIcon("Back24").get - mnemonic = new Integer(java.awt.event.KeyEvent.VK_L) - peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the left button.") - // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) - } - val middleAction = new Action("Do something") { - override def apply(): Unit = {} - icon = ActionDemo.createNavigationIcon("Up24").get - mnemonic = new Integer(java.awt.event.KeyEvent.VK_M) - peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the middle button.") - // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) - } - val rightAction = new Action("Go right") { - override def apply(): Unit = {} - icon = ActionDemo.createNavigationIcon("Forward24").get - mnemonic = new Integer(java.awt.event.KeyEvent.VK_R) - peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, "This is the right button.") - // peer.putValue(javax.swing.Action.MNEMONIC_KEY, mnemonic) - } - - def displayResult(actionDescription: String, source: String): Unit = { - val newline = "\n" - val s: String = "Action event detected: " + - actionDescription + - newline + - " Event source: " + source + - newline; - textArea.append(s); - } - - def createMenuBar(): MenuBar = { - //Create the menu bar. - val menuBar = new MenuBar() - - //Create the first menu. - val mainMenu = new Menu("Menu") - val actions = new Array[Action](3) - actions(0) = leftAction - actions(1) = middleAction - actions(2) = rightAction - val mi0 = new MenuItem(actions(0)) { icon = Swing.EmptyIcon } - val mi1 = new MenuItem(actions(1)) { icon = Swing.EmptyIcon } - val mi2 = new MenuItem(actions(2)) { icon = Swing.EmptyIcon } - mainMenu.contents += mi0 - mainMenu.contents += mi1 - mainMenu.contents += mi2 - listenTo(mi0) - listenTo(mi1) - listenTo(mi2) - reactions += { - case ButtonClicked(`mi0`) => displayResult("Action for first button/menu item", "Menu Item 1") - case ButtonClicked(`mi1`) => displayResult("Action for second button/menu item", "Menu Item 2") - case ButtonClicked(`mi2`) => displayResult("Action for third button/menu item", "Menu Item 3") - } - //Set up the menu bar. - menuBar.contents += mainMenu - menuBar.contents += createAbleMenu() - menuBar - } - - def createToolBar(): Unit = { - val toolBar = new ToolBar() - //first button - val button1 = new Button(leftAction) { - if (icon != null) text = "" // an icon-only button - } - val button2 = new Button(middleAction) { - if (icon != null) text = "" // an icon-only button - } - val button3 = new Button(rightAction) { - if (icon != null) text = "" // an icon-only button - } - toolBar.contents += button1 - toolBar.contents += button2 - toolBar.contents += button3 - layout(toolBar) = BorderPanel.Position.North - listenTo(button1) - listenTo(button2) - listenTo(button3) - reactions += { - case ButtonClicked(`button1`) => displayResult("Action for first button/menu item", "Toolbar button 1") - case ButtonClicked(`button2`) => displayResult("Action for second button/menu item", "Toolbar button 2") - case ButtonClicked(`button3`) => displayResult("Action for third button/menu item", "Toolbar button 3") - } - } - - def createAbleMenu(): Menu = { - val ableMenu = new Menu("Action State") - val cmi1 = new CheckMenuItem("First action enabled") { selected = true } - val cmi2 = new CheckMenuItem("Second action enabled") { selected = true } - val cmi3 = new CheckMenuItem("Third action enabled") { selected = true } - - ableMenu.contents += cmi1 - ableMenu.contents += cmi2 - ableMenu.contents += cmi3 - listenTo(cmi1) - listenTo(cmi2) - listenTo(cmi3) - reactions += { - case ButtonClicked(`cmi1`) => leftAction.enabled = cmi1.selected - case ButtonClicked(`cmi2`) => middleAction.enabled = cmi2.selected - case ButtonClicked(`cmi3`) => rightAction.enabled = cmi3.selected - } - ableMenu - } - -} - -object ActionDemo extends SimpleSwingApplication { - /** Returns an ImageIcon option, or None if the path was invalid. */ - def createNavigationIcon(imageName: String): Option[ImageIcon] = { - val imgLocation = "/toolbarButtonGraphics/navigation/" + imageName + ".gif" - val imageURL: URL = getClass().getResource(imgLocation) - if (imageURL == null) { - System.err.println("Resource not found: " + imgLocation) - return None - } else { - return Some(new ImageIcon(imageURL)) - } - } - - lazy val top = new MainFrame() { - title = "ActionDemo" - //Create and set up the content pane. - val demo = new ActionDemo() - menuBar = demo.createMenuBar() - demo.createToolBar() - contents = demo - } -}