Piggy 0.4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.txt +91 -0
- data/INSTALL.txt +77 -0
- data/LICENCE.txt +339 -0
- data/README.txt +27 -0
- data/UNINSTALL.txt +24 -0
- data/bin/directory_diff +6 -0
- data/bin/ftp_browser +6 -0
- data/bin/piggy +6 -0
- data/lib/directory_diff.rb +35 -0
- data/lib/ftp_browser.rb +33 -0
- data/lib/icons/auto-select-for-del.ico +0 -0
- data/lib/icons/auto-select-right.ico +0 -0
- data/lib/icons/auto-upload-right.ico +0 -0
- data/lib/icons/back.ico +0 -0
- data/lib/icons/checked.ico +0 -0
- data/lib/icons/copy.png +0 -0
- data/lib/icons/cut.png +0 -0
- data/lib/icons/dir.ico +0 -0
- data/lib/icons/dirup.ico +0 -0
- data/lib/icons/file.ico +0 -0
- data/lib/icons/fileopen.png +0 -0
- data/lib/icons/filesave.ico +0 -0
- data/lib/icons/gallery.ico +0 -0
- data/lib/icons/generate.ico +0 -0
- data/lib/icons/minus.png +0 -0
- data/lib/icons/move-right-dir.ico +0 -0
- data/lib/icons/move-right-file.ico +0 -0
- data/lib/icons/newer-file.ico +0 -0
- data/lib/icons/next-image.ico +0 -0
- data/lib/icons/paste.png +0 -0
- data/lib/icons/plus.png +0 -0
- data/lib/icons/preview.png +0 -0
- data/lib/icons/previous-image.ico +0 -0
- data/lib/icons/reload.ico +0 -0
- data/lib/icons/remove-selected.ico +0 -0
- data/lib/icons/rotate.ico +0 -0
- data/lib/icons/slides.ico +0 -0
- data/lib/icons/stop-slides.ico +0 -0
- data/lib/icons/unchecked-dir.ico +0 -0
- data/lib/icons/unchecked.ico +0 -0
- data/lib/icons/upload-selected.ico +0 -0
- data/lib/icons/upload.ico +0 -0
- data/lib/piggy-core/alive_check.rb +44 -0
- data/lib/piggy-core/debug.rb +21 -0
- data/lib/piggy-core/encoding.rb +11 -0
- data/lib/piggy-core/environment.rb +66 -0
- data/lib/piggy-core/exifr_adapter.rb +85 -0
- data/lib/piggy-core/file_info.rb +218 -0
- data/lib/piggy-core/ftp_adapter.rb +106 -0
- data/lib/piggy-core/htmlgen.rb +242 -0
- data/lib/piggy-core/nconvert_thumbsgen.rb +73 -0
- data/lib/piggy-core/options.rb +116 -0
- data/lib/piggy-core/options_persistence.rb +54 -0
- data/lib/piggy-core/progress.rb +48 -0
- data/lib/piggy-core/rmagick_thumbnail_page_generator.rb +30 -0
- data/lib/piggy-core/thumbnail_generator.rb +79 -0
- data/lib/piggy-core/thumbnail_page_generator.rb +542 -0
- data/lib/piggy-core/upload_info.rb +41 -0
- data/lib/piggy-core/version.rb +18 -0
- data/lib/piggy-core/winshell.rb +240 -0
- data/lib/piggy-gui/directory_diff_widget.rb +398 -0
- data/lib/piggy-gui/filtered_file_list.rb +243 -0
- data/lib/piggy-gui/fox_thumbsgen.rb +18 -0
- data/lib/piggy-gui/ftp_browser_widget.rb +395 -0
- data/lib/piggy-gui/html_generation_dialog.rb +157 -0
- data/lib/piggy-gui/image_processor.rb +140 -0
- data/lib/piggy-gui/multiimagecanvas.rb +163 -0
- data/lib/piggy-gui/options_dialog.rb +85 -0
- data/lib/piggy-gui/piggy_image_browser.rb +776 -0
- data/lib/piggy-gui/pipe_log.rb +67 -0
- data/lib/piggy-gui/progress_with_dialog.rb +51 -0
- data/lib/piggy-gui/require-fox.rb +87 -0
- data/lib/piggy.rb +35 -0
- data/lib/templates/fuss.htm +10 -0
- data/lib/templates/kopf.htm +13 -0
- data/lib/templates/navigation.htm +11 -0
- data/lib/templates/slideshow.htm +129 -0
- data/lib/templates/slideshow.js +691 -0
- data/lib/templates/styles/basic/style.css +27 -0
- data/lib/templates/styles/black/style.css +64 -0
- data/lib/templates/styles/roundedbox/roundedbox_lo.gif +0 -0
- data/lib/templates/styles/roundedbox/roundedbox_lu.gif +0 -0
- data/lib/templates/styles/roundedbox/roundedbox_ro.gif +0 -0
- data/lib/templates/styles/roundedbox/roundedbox_ru.gif +0 -0
- data/lib/templates/styles/roundedbox/style.css +70 -0
- data/lib/templates/styles/shadow/lo.gif +0 -0
- data/lib/templates/styles/shadow/lu.gif +0 -0
- data/lib/templates/styles/shadow/ro.gif +0 -0
- data/lib/templates/styles/shadow/ru.gif +0 -0
- data/lib/templates/styles/shadow/style.css +63 -0
- data/test/file_info_test.rb +117 -0
- data/test.rb +8 -0
- data/web/IMAGE_PROCESSING.txt +53 -0
- data/web/INSTALL.txt +74 -0
- data/web/extern.gif +0 -0
- data/web/ftp-browser.png +0 -0
- data/web/index-de.html +60 -0
- data/web/index.html +57 -0
- data/web/piggy.png +0 -0
- data/web/style.css +14 -0
- metadata +177 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
## $Id: html_generation_dialog.rb 190 2008-02-02 18:52:57Z Sascha $
|
|
3
|
+
|
|
4
|
+
# html_generation_dialog.rb includes the HtmlGenerationDialog which
|
|
5
|
+
# is part of piggy.
|
|
6
|
+
|
|
7
|
+
require 'piggy-core/options'
|
|
8
|
+
require 'piggy-core/winshell'
|
|
9
|
+
require 'piggy-gui/require-fox'
|
|
10
|
+
|
|
11
|
+
# Dialog for manipulation some of Piggy's html generation parameters.
|
|
12
|
+
class HtmlGenerationDialog < Fox::FXDialogBox
|
|
13
|
+
include Fox
|
|
14
|
+
Placement = PIGGY_WINDOW_PLACEMENT
|
|
15
|
+
|
|
16
|
+
attr_reader(:options)
|
|
17
|
+
|
|
18
|
+
def initialize(owner, options = PiggyOptions.new)
|
|
19
|
+
title = "Thumbnail page generator options"
|
|
20
|
+
@options = options
|
|
21
|
+
@shell = WinShell.instance
|
|
22
|
+
super(owner, title, DECOR_TITLE|DECOR_BORDER)
|
|
23
|
+
initializeVariables
|
|
24
|
+
initializeLayout
|
|
25
|
+
setDefaults
|
|
26
|
+
connectEvents
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initializeVariables
|
|
30
|
+
@frame = FXVerticalFrame.new(self)
|
|
31
|
+
@contents = FXMatrix.new(@frame, 2, MATRIX_BY_COLUMNS)
|
|
32
|
+
@labels = Array.new
|
|
33
|
+
@labels.push(FXLabel.new(@contents, "Output directory:"))
|
|
34
|
+
@outputPathField = FXTextField.new(@contents, 32)
|
|
35
|
+
@labels.push(FXLabel.new(@contents, "Framepage:"))
|
|
36
|
+
@genFrameRadioButtons = FXMatrix.new(@contents, 2, MATRIX_BY_COLUMNS)
|
|
37
|
+
@genFrameYes = FXRadioButton.new(@genFrameRadioButtons, "&Yes")
|
|
38
|
+
@genFrameNo = FXRadioButton.new(@genFrameRadioButtons, "&No")
|
|
39
|
+
@labels.push(FXLabel.new(@contents, "Title:"))
|
|
40
|
+
@titleField = FXTextField.new(@contents, 32)
|
|
41
|
+
@labels.push(FXLabel.new(@contents, "Subdirectory:"))
|
|
42
|
+
@subdirField = FXTextField.new(@contents, 32)
|
|
43
|
+
FXLabel.new(@contents, ""); # TODO empty cell in matrix layout
|
|
44
|
+
@addZipCheck = FXCheckButton.new(@contents, 'Add zipfile')
|
|
45
|
+
FXLabel.new(@contents, ""); # TODO empty cell in matrix layout
|
|
46
|
+
@addSlideshowCheck = FXCheckButton.new(@contents, 'Add slideshow')
|
|
47
|
+
@labels.push(FXLabel.new(@contents, "Style:"))
|
|
48
|
+
@styleTextField = newCombobox(@contents, 32,
|
|
49
|
+
10,
|
|
50
|
+
nil, 0, COMBOBOX_INSERT_LAST)
|
|
51
|
+
@styleTextField.setFrameStyle(FRAME_SUNKEN|FRAME_THICK)
|
|
52
|
+
@styleTextField.setLayoutHints(LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
|
|
53
|
+
@separator = FXHorizontalSeparator.new(@frame, SEPARATOR_GROOVE)
|
|
54
|
+
@buttons = FXHorizontalFrame.new(@frame)
|
|
55
|
+
@cancel = FXButton.new(@buttons, "&Cancel", nil, self, ID_CANCEL)
|
|
56
|
+
@accept = FXButton.new(@buttons, "&Accept", nil, self, ID_ACCEPT)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def initializeLayout
|
|
60
|
+
@labels.each { |label| label.setLayoutHints LAYOUT_CENTER_Y }
|
|
61
|
+
@buttons.setLayoutHints(LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X)
|
|
62
|
+
@buttons.setPackingHints(PACK_UNIFORM_WIDTH)
|
|
63
|
+
@accept.setLayoutHints(LAYOUT_RIGHT)
|
|
64
|
+
@cancel.setLayoutHints(LAYOUT_RIGHT)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def updateStylesList
|
|
68
|
+
styleDir = File.join(PIGGY_PATH, 'templates/styles')
|
|
69
|
+
@styleTextField.clearItems
|
|
70
|
+
Dir[File.join(styleDir, '*')].entries.reject { |f| f =~ /^\.+$/ }.each do
|
|
71
|
+
|folder|
|
|
72
|
+
@styleTextField.appendItem(File.basename(folder))
|
|
73
|
+
end
|
|
74
|
+
@styleTextField.setText(@options.style)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def setDefaults
|
|
78
|
+
@genFrameYes.setCheck(@options.generateFramePage)
|
|
79
|
+
@genFrameNo.setCheck(!@options.generateFramePage)
|
|
80
|
+
@outputPathField.setText(@shell.winPath(@options.localDestinationPath))
|
|
81
|
+
@addZipCheck.setCheck(@options.addZip?)
|
|
82
|
+
@addSlideshowCheck.setCheck(@options.addSlideshow?)
|
|
83
|
+
updateStylesList
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def connectEvents
|
|
87
|
+
@genFrameYes.connect(SEL_COMMAND) {
|
|
88
|
+
@genFrameNo.setCheck false
|
|
89
|
+
@options.generateFramePage = true
|
|
90
|
+
}
|
|
91
|
+
@genFrameNo.connect(SEL_COMMAND) {
|
|
92
|
+
@genFrameYes.setCheck false
|
|
93
|
+
@options.generateFramePage = false
|
|
94
|
+
}
|
|
95
|
+
@outputPathField.connect(SEL_COMMAND) {
|
|
96
|
+
@options.localDestinationPath = @shell.rubyPath(@outputPathField.getText)
|
|
97
|
+
}
|
|
98
|
+
@addZipCheck.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
99
|
+
@options.addZip = ptr
|
|
100
|
+
}
|
|
101
|
+
@addSlideshowCheck.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
102
|
+
@options.addSlideshow = ptr
|
|
103
|
+
}
|
|
104
|
+
@styleTextField.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
105
|
+
@options.style = ptr
|
|
106
|
+
validateStyle
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def getSubdir
|
|
111
|
+
return fox2Ruby(@subdirField.getText)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def getTitle
|
|
115
|
+
return fox2Ruby(@titleField.getText)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def validate
|
|
119
|
+
validateSubdir && validateStyle
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def validateSubdir # TODO wo aufrufen???
|
|
123
|
+
if getSubdir.empty?
|
|
124
|
+
warnNoSubdirGiven
|
|
125
|
+
return false
|
|
126
|
+
end
|
|
127
|
+
return true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def validateStyle
|
|
131
|
+
styleDir = File.join(PIGGY_PATH, 'templates/styles', @options.style)
|
|
132
|
+
unless File.directory?(styleDir)
|
|
133
|
+
warnStyleMissing
|
|
134
|
+
false
|
|
135
|
+
else
|
|
136
|
+
true
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def warnNoSubdirGiven
|
|
141
|
+
style = MBOX_OK|DECOR_TITLE|DECOR_CLOSE|Placement
|
|
142
|
+
title = "No subdirectory"
|
|
143
|
+
msg = "Specify a subdirectory first"
|
|
144
|
+
FXMessageBox::warning(self, style, title, msg)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def warnStyleMissing
|
|
148
|
+
style = MBOX_OK|DECOR_TITLE|DECOR_CLOSE|Placement
|
|
149
|
+
title = "Style not found"
|
|
150
|
+
msg = "Style missing: #{@options.style}"
|
|
151
|
+
FXMessageBox::warning(self, style, title, msg)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def execute(placement=Placement)
|
|
155
|
+
return super(placement) > 0 # TODO durch geeignete Konstante ersetzen
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
## $Id: image_processor.rb 190 2008-02-02 18:52:57Z Sascha $
|
|
3
|
+
|
|
4
|
+
require 'piggy-gui/require-fox'
|
|
5
|
+
|
|
6
|
+
# Utilizes image processing via FXRuby.
|
|
7
|
+
class ImageProcessor
|
|
8
|
+
include Fox
|
|
9
|
+
|
|
10
|
+
def initialize application
|
|
11
|
+
@app = application
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def isSupportedImageFile? file
|
|
15
|
+
return getImageClassForFile(file) != nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def loadIcon(file, create = true)
|
|
19
|
+
img = getIconInstanceForFile file
|
|
20
|
+
return basicLoad(img, file, create)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def loadImage(file, create = true)
|
|
24
|
+
img = getImageInstanceForFile file
|
|
25
|
+
return basicLoad(img, file, create)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def basicLoad(img, rubyfile, create)
|
|
29
|
+
return nil if img == nil
|
|
30
|
+
file = ruby2Fox(rubyfile)
|
|
31
|
+
begin
|
|
32
|
+
FXFileStream.open(file, FXStreamLoad) do
|
|
33
|
+
|stream|
|
|
34
|
+
img.loadPixels stream
|
|
35
|
+
end
|
|
36
|
+
img.create if create
|
|
37
|
+
rescue FXStreamNoReadError
|
|
38
|
+
puts "File not found: #{file}"
|
|
39
|
+
end
|
|
40
|
+
return img
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def saveImage(img, rubyfile)
|
|
44
|
+
file = ruby2Fox(rubyfile)
|
|
45
|
+
FXFileStream.open(file, FXStreamSave) do
|
|
46
|
+
|stream|
|
|
47
|
+
img.savePixels stream
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def uncreateImage(img)
|
|
52
|
+
img.destroy
|
|
53
|
+
img.release
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def destroyAll(imageCache)
|
|
57
|
+
imageCache.each { |i| uncreateImage(i) }
|
|
58
|
+
imageCache.clear
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def garbageImage(img)
|
|
62
|
+
uncreateImage(img)
|
|
63
|
+
GC.start
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def fitImage(img, maxW, maxH, quality = 1)
|
|
67
|
+
w = img.getWidth
|
|
68
|
+
h = img.getHeight
|
|
69
|
+
ratios = Array.new(2)
|
|
70
|
+
ratios[0] = maxW.to_f / w.to_f
|
|
71
|
+
ratios[1] = maxH.to_f / h.to_f
|
|
72
|
+
ratio = ratios.min
|
|
73
|
+
newW = (w * ratio).to_i
|
|
74
|
+
newH = (h * ratio).to_i
|
|
75
|
+
if newW < 10 or newH < 10
|
|
76
|
+
return false
|
|
77
|
+
end
|
|
78
|
+
img.scale(newW, newH, quality)
|
|
79
|
+
return true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def rotateImage(img, degree)
|
|
83
|
+
foxDegree = case degree
|
|
84
|
+
when 0 then 0
|
|
85
|
+
when 90 then 270
|
|
86
|
+
when 180 then 180
|
|
87
|
+
when 270 then 90
|
|
88
|
+
else
|
|
89
|
+
return error('Illegal degree')
|
|
90
|
+
end
|
|
91
|
+
img.rotate(foxDegree)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def hasExtension(filename, ext)
|
|
97
|
+
File.basename(filename.upcase, ext.upcase) !=
|
|
98
|
+
File.basename(filename.upcase)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def getImageClassForFile(file)
|
|
102
|
+
return FXGIFImage if hasExtension(file, ".gif")
|
|
103
|
+
return FXBMPImage if hasExtension(file, ".bmp")
|
|
104
|
+
return FXXPMImage if hasExtension(file, ".xpm")
|
|
105
|
+
return FXPNGImage if hasExtension(file, ".png")
|
|
106
|
+
return FXJPGImage if hasExtension(file, ".jpg")
|
|
107
|
+
return FXPCXImage if hasExtension(file, ".pcx")
|
|
108
|
+
return FXTIFImage if hasExtension(file, ".tif")
|
|
109
|
+
return FXTGAImage if hasExtension(file, ".tga")
|
|
110
|
+
return FXICOImage if hasExtension(file, ".ico")
|
|
111
|
+
return nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def getIconClassForFile(file)
|
|
115
|
+
return FXGIFIcon if hasExtension(file, ".gif")
|
|
116
|
+
return FXBMPIcon if hasExtension(file, ".bmp")
|
|
117
|
+
return FXXPMIcon if hasExtension(file, ".xpm")
|
|
118
|
+
return FXPNGIcon if hasExtension(file, ".png")
|
|
119
|
+
return FXJPGIcon if hasExtension(file, ".jpg")
|
|
120
|
+
return FXPCXIcon if hasExtension(file, ".pcx")
|
|
121
|
+
return FXTIFIcon if hasExtension(file, ".tif")
|
|
122
|
+
return FXTGAIcon if hasExtension(file, ".tga")
|
|
123
|
+
return FXICOIcon if hasExtension(file, ".ico")
|
|
124
|
+
return nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def getImageInstanceForFile(file)
|
|
128
|
+
imageClass = getImageClassForFile file
|
|
129
|
+
return nil if !imageClass
|
|
130
|
+
return imageClass.new(@app, nil, IMAGE_KEEP|
|
|
131
|
+
IMAGE_OWNED|IMAGE_SHMI|IMAGE_SHMP
|
|
132
|
+
)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def getIconInstanceForFile(file)
|
|
136
|
+
iconClass = getIconClassForFile file
|
|
137
|
+
return nil if !iconClass
|
|
138
|
+
return iconClass.new(@app, nil)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
## $Id: multiimagecanvas.rb 196 2008-05-29 22:01:04Z Sascha $
|
|
3
|
+
|
|
4
|
+
# The following post by Patrick Hurley was quite useful:
|
|
5
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/178054
|
|
6
|
+
|
|
7
|
+
require 'piggy-gui/image_processor'
|
|
8
|
+
|
|
9
|
+
# Shows multiple images in a sigle widget.
|
|
10
|
+
class MultiImageCanvas < Fox::FXScrollWindow
|
|
11
|
+
include Responder
|
|
12
|
+
include Fox
|
|
13
|
+
CacheSize = 200
|
|
14
|
+
|
|
15
|
+
def initialize(p1, p2)
|
|
16
|
+
super(p1, p2)
|
|
17
|
+
drawArea = FXCanvas.new(self, nil, 0,
|
|
18
|
+
FRAME_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y)
|
|
19
|
+
drawArea.connect(SEL_PAINT, method(:onPaint))
|
|
20
|
+
@contentWidth = width
|
|
21
|
+
@contentHeight = height
|
|
22
|
+
@images = Array.new
|
|
23
|
+
@buffer = nil
|
|
24
|
+
@thumbs = Hash.new
|
|
25
|
+
@fifoThumbsKeys = Array.new
|
|
26
|
+
@imgProcessor = ImageProcessor.new getApp
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def destroyAll(imageCache)
|
|
30
|
+
@imgProcessor.destroyAll(imageCache)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def imageProcessor
|
|
34
|
+
return @imgProcessor
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def getContentWidth
|
|
38
|
+
return @contentWidth
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def getContentHeight
|
|
42
|
+
return @contentHeight
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def images
|
|
46
|
+
return @images
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def image
|
|
50
|
+
return @images.empty? ? nil : @images[0]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def setImages(imageArray)
|
|
54
|
+
@images = imageArray
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def loadAndShowImage(file)
|
|
58
|
+
loadImage(file)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def loadImage(file, additive=false, degree=0)
|
|
62
|
+
if additive && @thumbs.has_key?(file)
|
|
63
|
+
images.push(@thumbs[file])
|
|
64
|
+
return
|
|
65
|
+
end
|
|
66
|
+
if !@imgProcessor.isSupportedImageFile? file
|
|
67
|
+
FXMessageBox.error(self, MBOX_OK, "Warning image type",
|
|
68
|
+
"Unsupported image type: #{file}")
|
|
69
|
+
return
|
|
70
|
+
end
|
|
71
|
+
getApp.beginWaitCursor do
|
|
72
|
+
img = @imgProcessor.loadImage(file, false)
|
|
73
|
+
unless degree == 0
|
|
74
|
+
@imgProcessor.rotateImage(img, degree)
|
|
75
|
+
end
|
|
76
|
+
destroyAll(@images) if !additive
|
|
77
|
+
images.push(img)
|
|
78
|
+
if additive
|
|
79
|
+
cacheThumbFor(file, img)
|
|
80
|
+
else
|
|
81
|
+
w = img.getWidth
|
|
82
|
+
h = img.getHeight
|
|
83
|
+
if(w > 1600 && h > 1000)
|
|
84
|
+
# reduce footprint
|
|
85
|
+
@imgProcessor.fitImage(img, 1600, 1000, 1)
|
|
86
|
+
end
|
|
87
|
+
FXMemoryStream.open(FXStreamSave, nil) do |stream|
|
|
88
|
+
img.savePixels(stream)
|
|
89
|
+
@buffer = stream.takeBuffer
|
|
90
|
+
end
|
|
91
|
+
@imgProcessor.fitImage(img, getWidth, getHeight, 1)
|
|
92
|
+
end
|
|
93
|
+
img.create
|
|
94
|
+
forceRefresh if !additive
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def cacheThumbFor(file, img)
|
|
99
|
+
@imgProcessor.fitImage(img, 100, 100, 0)
|
|
100
|
+
@thumbs[file] = img
|
|
101
|
+
@fifoThumbsKeys.push(file)
|
|
102
|
+
if @fifoThumbsKeys.size > CacheSize
|
|
103
|
+
thumbToDestroy = @fifoThumbsKeys.shift
|
|
104
|
+
@thumbs[thumbToDestroy].destroy
|
|
105
|
+
@thumbs.delete(thumbToDestroy)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def fit
|
|
110
|
+
img = image
|
|
111
|
+
w = getWidth
|
|
112
|
+
h = getHeight
|
|
113
|
+
return if img.nil? || w < 5 || h < 5
|
|
114
|
+
FXMemoryStream.open(FXStreamLoad, @buffer) do |stream|
|
|
115
|
+
img.loadPixels(stream)
|
|
116
|
+
end
|
|
117
|
+
@imgProcessor.fitImage(img, w, h)
|
|
118
|
+
forceRefresh
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def loadImages(files)
|
|
122
|
+
images.clear
|
|
123
|
+
files.each { |f| loadImage(f, true) }
|
|
124
|
+
forceRefresh
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def forceRefresh
|
|
128
|
+
contentWindow.update
|
|
129
|
+
contentWindow.repaint
|
|
130
|
+
contentWindow.recalc
|
|
131
|
+
repaint
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def onPaint(sender, sel, unused)
|
|
135
|
+
sdc = FXDCWindow.new(contentWindow)
|
|
136
|
+
sdc.fillRectangle(0, 0, width, height)
|
|
137
|
+
unless images.empty? || width < 5 || height < 5
|
|
138
|
+
# Draw image table
|
|
139
|
+
x = 0;
|
|
140
|
+
y = 0;
|
|
141
|
+
lineHeight = 0
|
|
142
|
+
subWidth = images.size == 1 ? 0 : 16 # width for vScrollbar
|
|
143
|
+
maxW = [images[0].width + subWidth, width].max
|
|
144
|
+
images.each { |img|
|
|
145
|
+
imgHeight = img.height
|
|
146
|
+
imgWidth = img.width
|
|
147
|
+
maxW = imgWidth if imgWidth + subWidth > maxW
|
|
148
|
+
if x + img.width > maxW - subWidth
|
|
149
|
+
x = 0
|
|
150
|
+
y += lineHeight + 4
|
|
151
|
+
lineHeight = 0
|
|
152
|
+
end
|
|
153
|
+
lineHeight = imgHeight if imgHeight > lineHeight
|
|
154
|
+
sdc.drawImage(img, x, y)
|
|
155
|
+
sdc.fillRectangle(x, y + imgHeight, x + imgWidth, y + lineHeight)
|
|
156
|
+
x += imgWidth + 4
|
|
157
|
+
}
|
|
158
|
+
@contentWidth = maxW
|
|
159
|
+
@contentHeight = y + lineHeight
|
|
160
|
+
end
|
|
161
|
+
sdc.end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
## $Id: options_dialog.rb 161 2006-12-23 15:41:01Z Sascha $
|
|
3
|
+
|
|
4
|
+
# options_dialog.rb includes the OptionsDialog which is part of piggy.
|
|
5
|
+
|
|
6
|
+
require 'piggy-core/environment'
|
|
7
|
+
require 'piggy-core/options'
|
|
8
|
+
require 'piggy-gui/require-fox'
|
|
9
|
+
|
|
10
|
+
# Dialog to change some of Piggy's options.
|
|
11
|
+
class OptionsDialog < Fox::FXDialogBox
|
|
12
|
+
include Fox
|
|
13
|
+
|
|
14
|
+
attr_reader(:options)
|
|
15
|
+
|
|
16
|
+
def initialize(owner, piggyOptions)
|
|
17
|
+
title = "Piggy general options"
|
|
18
|
+
super(owner, title, DECOR_TITLE|DECOR_BORDER|PIGGY_WINDOW_PLACEMENT)
|
|
19
|
+
@options = piggyOptions.clone
|
|
20
|
+
@fillMode = LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_Y
|
|
21
|
+
@frameStyle = FRAME_NONE
|
|
22
|
+
initializeLayout
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def initFrame(aFrame)
|
|
26
|
+
aFrame.setFrameStyle(@frameStyle)
|
|
27
|
+
aFrame.setLayoutHints(@fillMode)
|
|
28
|
+
return aFrame
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def initializeLayout
|
|
32
|
+
basicFrame = FXVerticalFrame.new(self)
|
|
33
|
+
cbFlags = ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP
|
|
34
|
+
|
|
35
|
+
FXLabel.new(basicFrame, "Image processing:")
|
|
36
|
+
radioButtonsFrame = initFrame(FXVerticalFrame.new(basicFrame))
|
|
37
|
+
@rbFxruby = FXRadioButton.new(radioButtonsFrame, "Internal (FXRuby)")
|
|
38
|
+
@rbNconvert = FXRadioButton.new(radioButtonsFrame, "NConvert (XNView)")
|
|
39
|
+
@rbRmagick = FXRadioButton.new(radioButtonsFrame, "RMagick")
|
|
40
|
+
updateProcessor
|
|
41
|
+
@rbFxruby.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
42
|
+
@options.useFxruby!
|
|
43
|
+
updateProcessor
|
|
44
|
+
}
|
|
45
|
+
@rbNconvert.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
46
|
+
@options.useNconvert!
|
|
47
|
+
updateProcessor
|
|
48
|
+
}
|
|
49
|
+
if RMAGICK_AVAILIABLE
|
|
50
|
+
@rbRmagick.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
51
|
+
@options.useRmagick!
|
|
52
|
+
updateProcessor
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
@rbRmagick.disable
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
FXLabel.new(basicFrame, "Main window:")
|
|
59
|
+
|
|
60
|
+
cb = FXCheckButton.new(basicFrame,
|
|
61
|
+
'Show log pane',
|
|
62
|
+
nil, 0, cbFlags)
|
|
63
|
+
cb.setCheck(@options.useLog)
|
|
64
|
+
cb.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
65
|
+
@options.useLog = ptr
|
|
66
|
+
}
|
|
67
|
+
cb = FXCheckButton.new(basicFrame,
|
|
68
|
+
'Show preview pane (experimental)',
|
|
69
|
+
nil, 0, cbFlags)
|
|
70
|
+
cb.setCheck(@options.usePreview)
|
|
71
|
+
cb.connect(SEL_COMMAND) { |sender, sel, ptr|
|
|
72
|
+
@options.usePreview = ptr
|
|
73
|
+
}
|
|
74
|
+
buttons = FXHorizontalFrame.new(basicFrame)
|
|
75
|
+
@accept = FXButton.new(buttons, "&Accept", nil, self, ID_ACCEPT)
|
|
76
|
+
@cancel = FXButton.new(buttons, "&Cancel", nil, self, ID_CANCEL)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def updateProcessor
|
|
80
|
+
@rbFxruby.setCheck(@options.useFxruby?)
|
|
81
|
+
@rbNconvert.setCheck(@options.useNconvert?)
|
|
82
|
+
@rbRmagick.setCheck(@options.useRmagick?)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|