author | tz |
Fri, 23 Jan 1998 14:58:30 +0100 | |
changeset 678 | 9afa8810a8be |
parent 676 | fd7918a3e6e6 |
child 686 | 33833bcbb5cd |
permissions | -rw-r--r-- |
636 | 1 |
" |
2 |
COPYRIGHT (c) 1997 by eXept Software AG / Thomas Zwick |
|
3 |
All Rights Reserved |
|
4 |
||
5 |
This software is furnished under a license and may be used |
|
6 |
only in accordance with the terms of that license and with the |
|
7 |
inclusion of the above copyright notice. This software may not |
|
8 |
be provided or otherwise made available to, or used by, any |
|
9 |
other person. No title to or ownership of the software is |
|
10 |
hereby transferred. |
|
11 |
" |
|
12 |
||
1 | 13 |
ImageView subclass:#ImageEditView |
627 | 14 |
instanceVariableNames:'magnification gridMagnification selectColors imageReaderClass |
15 |
resourceClass resourceSelector editMode mouseKeyColorMode |
|
662 | 16 |
undoImage modified coordInfoBlock masterApplication' |
627 | 17 |
classVariableNames:'Clipboard' |
161 | 18 |
poolDictionaries:'' |
19 |
category:'Views-Misc' |
|
1 | 20 |
! |
21 |
||
636 | 22 |
!ImageEditView class methodsFor:'documentation'! |
23 |
||
24 |
copyright |
|
25 |
" |
|
26 |
COPYRIGHT (c) 1997 by eXept Software AG / Thomas Zwick |
|
27 |
All Rights Reserved |
|
28 |
||
29 |
This software is furnished under a license and may be used |
|
30 |
only in accordance with the terms of that license and with the |
|
31 |
inclusion of the above copyright notice. This software may not |
|
32 |
be provided or otherwise made available to, or used by, any |
|
33 |
other person. No title to or ownership of the software is |
|
34 |
hereby transferred. |
|
35 |
" |
|
36 |
! |
|
37 |
||
38 |
documentation |
|
39 |
" |
|
40 |
The ImageEditView is a view class which can be used by applications |
|
41 |
like the Image Editor for modifying or inspecting images. |
|
42 |
||
43 |
[see also:] |
|
44 |
ImageEditor Image |
|
45 |
||
46 |
[author:] |
|
47 |
Thomas Zwick |
|
48 |
" |
|
49 |
! ! |
|
353 | 50 |
|
7 | 51 |
!ImageEditView methodsFor:'accessing'! |
52 |
||
627 | 53 |
coordInfoBlock: aBlock |
624 | 54 |
|
627 | 55 |
coordInfoBlock := aBlock |
624 | 56 |
! |
57 |
||
627 | 58 |
gridMagnification: aPoint |
624 | 59 |
|
627 | 60 |
gridMagnification := aPoint |
624 | 61 |
! |
62 |
||
63 |
imageReaderClass |
|
64 |
||
65 |
^imageReaderClass |
|
66 |
! |
|
67 |
||
68 |
magnification |
|
69 |
||
70 |
^magnification |
|
71 |
||
255 | 72 |
! |
73 |
||
636 | 74 |
magnification: aPoint |
255 | 75 |
|
627 | 76 |
magnification ~= aPoint |
624 | 77 |
ifTrue: |
78 |
[ |
|
627 | 79 |
magnification := aPoint asPoint. |
624 | 80 |
self scrollToTopLeft. |
81 |
self contentsChanged. |
|
82 |
self invalidate. |
|
83 |
]. |
|
84 |
! |
|
255 | 85 |
|
662 | 86 |
masterApplication |
87 |
||
88 |
^masterApplication |
|
89 |
! |
|
90 |
||
91 |
masterApplication: anApplicationModel |
|
92 |
||
93 |
masterApplication := anApplicationModel |
|
94 |
! |
|
95 |
||
627 | 96 |
resourceClass |
97 |
||
98 |
^resourceClass |
|
99 |
! |
|
100 |
||
101 |
resourceClass: aClassOrSymbol |
|
102 |
||
103 |
resourceClass := aClassOrSymbol isClass ifTrue: [aClassOrSymbol name] ifFalse: [aClassOrSymbol asSymbol]. |
|
104 |
! |
|
105 |
||
106 |
resourceMessage |
|
107 |
||
108 |
^resourceClass, ' ', resourceSelector |
|
109 |
! |
|
110 |
||
636 | 111 |
resourceMessage: aString |
627 | 112 |
|
636 | 113 |
(aString isString and: [aString trimBlanks size > 0]) |
627 | 114 |
ifTrue: |
115 |
[ |
|
636 | 116 |
resourceClass := (aString readStream upTo: Character space) asSymbol. |
117 |
resourceSelector := (aString copy reverse readStream upTo: Character space) reverse asSymbol. |
|
627 | 118 |
] |
119 |
ifFalse: |
|
120 |
[ |
|
121 |
^nil |
|
122 |
]. |
|
123 |
||
124 |
||
125 |
! |
|
126 |
||
127 |
resourceSelector |
|
128 |
||
129 |
^resourceSelector |
|
130 |
! |
|
131 |
||
132 |
resourceSelector: aStringOrSymbol |
|
133 |
||
134 |
resourceSelector := aStringOrSymbol asSymbol |
|
135 |
! |
|
136 |
||
633 | 137 |
selectColor: anArrayTwoColors |
138 |
||
139 |
selectColors := anArrayTwoColors |
|
140 |
! |
|
141 |
||
627 | 142 |
selectedColor |
143 |
||
633 | 144 |
^selectColors at: mouseKeyColorMode |
627 | 145 |
! |
146 |
||
147 |
selectedColor: aColor |
|
148 |
||
149 |
selectColors at: mouseKeyColorMode put: aColor |
|
150 |
! ! |
|
151 |
||
152 |
!ImageEditView methodsFor:'drawing'! |
|
153 |
||
662 | 154 |
fillFramedRectangle: aRectangle |
155 |
||
156 |
self fillRectangle: aRectangle. |
|
157 |
self drawFramesIn: aRectangle |
|
158 |
! |
|
159 |
||
627 | 160 |
redrawImageX:x y:y width:w height:h |
636 | 161 |
|
662 | 162 |
|ih iw magX magY minX maxX minY maxY color lastColor lastY runW x0 xI yI maskColor sizeOfMaskPoint| |
627 | 163 |
|
164 |
ih := image height. |
|
165 |
iw := image width. |
|
662 | 166 |
magX := magnification x. |
167 |
magY := magnification y. |
|
627 | 168 |
|
662 | 169 |
minX := (x // magX - 1) max: 0. |
627 | 170 |
minX >= iw ifTrue:[minX := iw - 1]. |
662 | 171 |
minY := (y // magY - 1) max: 0. |
627 | 172 |
minY >= ih ifTrue:[minY := ih - 1]. |
662 | 173 |
maxX := (x + w) // magX + 1. |
627 | 174 |
maxX > iw ifTrue:[maxX := iw]. |
662 | 175 |
maxY := (y + h) // magY + 1. |
627 | 176 |
maxY > ih ifTrue:[maxY := ih]. |
177 |
||
178 |
lastY := -1. |
|
179 |
||
180 |
x0 := minX. |
|
181 |
runW := 0. |
|
182 |
maskColor := false. |
|
662 | 183 |
sizeOfMaskPoint := magnification//3. |
184 |
image colorsFromX: minX y: minY toX: maxX-1 y: maxY-1 do: |
|
627 | 185 |
[:xx :yy :color| |
633 | 186 |
yy ~~ lastY |
187 |
ifTrue: |
|
627 | 188 |
[ |
633 | 189 |
runW ~~ 0 |
190 |
ifTrue: |
|
627 | 191 |
[ |
192 |
|origin| |
|
662 | 193 |
origin := (x0 * magX + margin)@(lastY * magY + margin). |
194 |
self fillFramedRectangle: (origin extent: (runW@magY)). |
|
627 | 195 |
maskColor ifTrue: |
196 |
[ |
|
662 | 197 |
self xoring: [self fillRectangle: (origin + sizeOfMaskPoint extent: sizeOfMaskPoint)] |
627 | 198 |
]. |
199 |
runW := 0. |
|
200 |
]. |
|
201 |
x0 := xx. |
|
202 |
lastY := yy. |
|
203 |
]. |
|
624 | 204 |
|
662 | 205 |
color ~~ lastColor |
633 | 206 |
ifTrue: |
627 | 207 |
[ |
633 | 208 |
runW ~~ 0 |
209 |
ifTrue: |
|
627 | 210 |
[ |
211 |
|origin| |
|
662 | 212 |
origin := (x0 * magX + margin)@(yy * magY + margin). |
213 |
self fillFramedRectangle: (origin extent: (runW@magY)). |
|
627 | 214 |
maskColor ifTrue: |
215 |
[ |
|
662 | 216 |
self xoring: [self fillRectangle: (origin + sizeOfMaskPoint extent: sizeOfMaskPoint)] |
627 | 217 |
]. |
218 |
runW := 0. |
|
219 |
]. |
|
220 |
||
662 | 221 |
self paint: (lastColor := color). |
627 | 222 |
image mask notNil ifTrue: |
223 |
[ |
|
224 |
maskColor := false. |
|
225 |
(image mask colorAt: xx@yy) = Color black ifTrue: |
|
226 |
[ |
|
662 | 227 |
self paint: (lastColor := self viewBackground). |
627 | 228 |
maskColor := true. |
229 |
]. |
|
662 | 230 |
lastColor := nil. |
627 | 231 |
]. |
232 |
runW := 0. |
|
233 |
x0 := xx. |
|
234 |
]. |
|
662 | 235 |
runW := runW + magX |
627 | 236 |
]. |
237 |
runW ~~ 0 ifTrue: |
|
238 |
[ |
|
239 |
|origin| |
|
662 | 240 |
origin := (x0 * magX + margin)@(lastY * magY + margin). |
241 |
self fillFramedRectangle: (origin extent: runW@magY). |
|
627 | 242 |
maskColor ifTrue: |
243 |
[ |
|
662 | 244 |
self xoring: [self fillRectangle: (origin + sizeOfMaskPoint extent: sizeOfMaskPoint)] |
627 | 245 |
]. |
246 |
runW := 0. |
|
247 |
]. |
|
248 |
! |
|
249 |
||
250 |
redrawX:x y:y width:w height:h |
|
636 | 251 |
|
627 | 252 |
|ih iw xI yI| |
253 |
||
662 | 254 |
magnification = (1@1) ifTrue: [^super redrawX:x y:y width:w height:h]. |
255 |
||
627 | 256 |
image isNil ifTrue:[^self]. |
257 |
||
662 | 258 |
self clippingRectangle: (x@y extent: w@h). |
627 | 259 |
|
260 |
self redrawImageX:x y:y width:w height:h. |
|
261 |
||
262 |
"/ right of image ? |
|
263 |
adjust == #center ifTrue: |
|
264 |
[ |
|
633 | 265 |
xI := (width - ih) // 2 - margin. |
266 |
yI := (height - iw) // 2 - margin. |
|
627 | 267 |
] |
268 |
ifFalse: |
|
269 |
[ |
|
270 |
xI := yI := margin |
|
271 |
]. |
|
272 |
(x + w - 1) > (xI + (magnification x * image width)) ifTrue: |
|
273 |
[ |
|
274 |
self clearRectangleX:(xI + (magnification x * image width)) |
|
275 |
y:y |
|
276 |
width:(x + w - (magnification x * image width) - xI) |
|
277 |
height:h |
|
278 |
]. |
|
279 |
(y + h - 1) > (yI + (magnification y * image height)) ifTrue: |
|
280 |
[ |
|
281 |
self clearRectangleX:margin |
|
282 |
y:(yI + (magnification y * image height)) |
|
283 |
width:w |
|
284 |
height:(y + h - (magnification y * image height) - yI) |
|
285 |
]. |
|
286 |
self drawFrame. |
|
287 |
self clippingRectangle: nil. |
|
288 |
! ! |
|
289 |
||
290 |
!ImageEditView methodsFor:'edit modes'! |
|
291 |
||
292 |
editMode |
|
293 |
||
636 | 294 |
^editMode ? (editMode := 'point') |
627 | 295 |
! |
296 |
||
297 |
editMode:aMode |
|
298 |
||
299 |
editMode := aMode |
|
300 |
! |
|
301 |
||
302 |
mouseKeyColorMode |
|
303 |
||
304 |
^mouseKeyColorMode printString |
|
305 |
! |
|
306 |
||
307 |
mouseKeyColorMode:aMode |
|
308 |
||
309 |
mouseKeyColorMode := aMode asInteger |
|
310 |
! ! |
|
311 |
||
312 |
!ImageEditView methodsFor:'event handling'! |
|
313 |
||
314 |
buttonMotion:state x:x y:y |
|
315 |
||
632 | 316 |
self drawCursorAt: x@y. |
627 | 317 |
self selectedColor notNil & image notNil & (self imageContainsPoint: x@y) & (editMode = 'point') |
318 |
ifTrue: [^self pointAt: x@y]. |
|
624 | 319 |
! |
255 | 320 |
|
627 | 321 |
buttonPress:button x:x y:y |
322 |
||
632 | 323 |
self drawCursorAt: x@y. |
627 | 324 |
self selectedColor notNil & image notNil & (self imageContainsPoint: x@y) |
325 |
ifTrue: |
|
632 | 326 |
[ |
627 | 327 |
undoImage := image copy. |
328 |
mouseKeyColorMode := button. |
|
632 | 329 |
self perform: (editMode, 'At:') asSymbol with: x@y. |
627 | 330 |
]. |
632 | 331 |
! |
332 |
||
333 |
buttonRelease:state x:x y:y |
|
334 |
||
335 |
Cursor normal show |
|
627 | 336 |
! ! |
337 |
||
636 | 338 |
!ImageEditView methodsFor:'image editing'! |
627 | 339 |
|
340 |
boxAt: aPoint |
|
341 |
||
662 | 342 |
|choosedBox imageBox| |
636 | 343 |
choosedBox := self drawRectangleStartingAt: aPoint emphasis: #box. |
662 | 344 |
image rectangle: (imageBox := choosedBox origin//magnification extent: (choosedBox extent//magnification)) withColor: self selectedColor. |
632 | 345 |
image restored. |
662 | 346 |
self redraw: (choosedBox expandedBy: 1). |
347 |
masterApplication notNil |
|
348 |
ifTrue: |
|
349 |
[ |
|
676 | 350 |
masterApplication imagePreView redraw: (imageBox expandedBy: 1) |
662 | 351 |
]. |
676 | 352 |
modified := true |
632 | 353 |
! |
354 |
||
355 |
copyAt: aPoint |
|
356 |
||
357 |
|choosedBox| |
|
636 | 358 |
choosedBox := self drawRectangleStartingAt: aPoint emphasis: #inverseFilledBox. |
632 | 359 |
Clipboard := image subImageIn: (choosedBox origin//magnification extent: (choosedBox extent//magnification)). |
662 | 360 |
self redraw: (choosedBox expandedBy: 1) |
632 | 361 |
|
362 |
! |
|
363 |
||
364 |
fillAt: aPoint |
|
627 | 365 |
|
632 | 366 |
Cursor execute showWhile: |
367 |
[ |
|
368 |
|filledPoints| |
|
369 |
filledPoints := image floodFillAt: aPoint//magnification withColor: self selectedColor. |
|
370 |
image restored. |
|
633 | 371 |
filledPoints size < 300 |
632 | 372 |
ifTrue: |
373 |
[ |
|
662 | 374 |
filledPoints do: [:p| self redraw: ((p * magnification extent: magnification) expandedBy: 1)] |
632 | 375 |
] |
376 |
ifFalse: |
|
377 |
[ |
|
378 |
self invalidate |
|
379 |
]. |
|
662 | 380 |
masterApplication notNil |
381 |
ifTrue: |
|
382 |
[ |
|
383 |
masterApplication imagePreView invalidate |
|
384 |
]. |
|
632 | 385 |
modified := true |
386 |
] |
|
387 |
! |
|
388 |
||
389 |
filledBoxAt: aPoint |
|
390 |
||
662 | 391 |
|choosedBox imageBox| |
636 | 392 |
choosedBox := self drawRectangleStartingAt: aPoint emphasis: #filledBox. |
662 | 393 |
image fillRectangle: (imageBox := choosedBox origin//magnification extent: (choosedBox extent//magnification)) withColor: self selectedColor. |
632 | 394 |
image restored. |
662 | 395 |
self redraw: (choosedBox expandedBy: 1). |
396 |
masterApplication notNil |
|
397 |
ifTrue: |
|
398 |
[ |
|
676 | 399 |
masterApplication imagePreView redraw: (imageBox expandedBy: 1) |
662 | 400 |
|
401 |
]. |
|
632 | 402 |
modified := true. |
403 |
! |
|
404 |
||
636 | 405 |
flipHorizontal |
406 |
||
407 |
undoImage := image copy. |
|
408 |
self image: image flipHorizontal |
|
409 |
||
410 |
! |
|
411 |
||
412 |
flipVertical |
|
413 |
||
414 |
undoImage := image copy. |
|
415 |
self image: image flipVertical |
|
416 |
||
417 |
! |
|
418 |
||
419 |
magnifyImage |
|
420 |
||
421 |
|box newSize| |
|
422 |
box := EnterBox new. |
|
423 |
box title:'Image new size:'. |
|
424 |
box okText:'OK'. |
|
425 |
box abortText:'Cancel'. |
|
426 |
box initialText:image extent printString. |
|
427 |
box showAtPointer. |
|
428 |
(box accepted and: [(newSize := Object readFromString: box contents onError:nil) notNil]) |
|
429 |
ifTrue: |
|
430 |
[ |
|
431 |
undoImage := image copy. |
|
432 |
self image: (image magnifiedBy: newSize/image extent) |
|
433 |
]. |
|
434 |
! |
|
435 |
||
436 |
negativeImage |
|
437 |
||
438 |
undoImage := image copy. |
|
439 |
self image: image negative |
|
440 |
||
441 |
! |
|
442 |
||
443 |
pasteAt: aPoint |
|
444 |
||
445 |
Object errorSignal handle: |
|
446 |
[:ex| |
|
447 |
self warn: 'Pasting at selected point failed!!' |
|
448 |
] |
|
449 |
do: |
|
450 |
[ |
|
662 | 451 |
|imagePoint imageBox| |
636 | 452 |
imagePoint := aPoint//magnification. |
453 |
image copyFrom: Clipboard x:0 y:0 toX: imagePoint x y: imagePoint y width: Clipboard width height: Clipboard height. |
|
454 |
image restored. |
|
662 | 455 |
self redraw: (imageBox := (imagePoint * magnification extent: (Clipboard extent * magnification)) expandedBy: 1@1). |
456 |
masterApplication notNil |
|
457 |
ifTrue: |
|
458 |
[ |
|
676 | 459 |
masterApplication imagePreView redraw: (imageBox expandedBy: 1) |
662 | 460 |
]. |
636 | 461 |
self drawLabel: imagePoint. |
676 | 462 |
modified := true |
636 | 463 |
] |
464 |
! |
|
465 |
||
466 |
pointAt: aPoint |
|
467 |
||
662 | 468 |
|imagePoint imageBox| |
636 | 469 |
imagePoint := aPoint//magnification. |
470 |
image atImageAndMask: imagePoint put: self selectedColor. |
|
471 |
image restored. |
|
662 | 472 |
self redraw: (imageBox := (imagePoint * magnification extent: magnification) expandedBy: 1). |
473 |
masterApplication notNil |
|
474 |
ifTrue: |
|
676 | 475 |
[ |
476 |
masterApplication imagePreView redraw: ((imagePoint + 1) extent: 1@1) |
|
662 | 477 |
]. |
636 | 478 |
self drawLabel: imagePoint. |
479 |
modified := true. |
|
480 |
! |
|
481 |
||
482 |
resizeImage |
|
483 |
||
484 |
|box newSize| |
|
485 |
box := EnterBox new. |
|
486 |
box title:'Image new size:'. |
|
487 |
box okText:'OK'. |
|
488 |
box abortText:'Cancel'. |
|
489 |
box initialText:image extent printString. |
|
490 |
box showAtPointer. |
|
491 |
(box accepted and: [(newSize := Object readFromString: box contents onError:nil) notNil]) |
|
492 |
ifTrue: |
|
493 |
[ |
|
494 |
|newImage| |
|
495 |
undoImage := image copy. |
|
496 |
newImage := image class width: newSize x height: newSize y depth: image depth. |
|
497 |
newImage photometric:image photometric. |
|
498 |
newImage colorMap:image colorMap copy. |
|
499 |
newImage bits: (ByteArray new: newImage bytesPerRow * newSize y). |
|
500 |
||
501 |
image mask notNil |
|
502 |
ifTrue: |
|
503 |
[ |
|
504 |
|newMaskImage| |
|
505 |
newMaskImage := Depth1Image width: newSize x height: newSize y. |
|
506 |
newMaskImage photometric: image mask photometric. |
|
507 |
newMaskImage colorMap: image mask colorMap copy. |
|
508 |
newMaskImage bits:(ByteArray new: newMaskImage bytesPerRow * newSize y). |
|
509 |
newImage mask: newMaskImage |
|
510 |
]. |
|
511 |
||
512 |
newImage copyFrom:image x:0 y:0 toX:0 y:0 width: (image width min:newSize x) height: (image height min:newSize y). |
|
513 |
self image: newImage |
|
514 |
]. |
|
515 |
! |
|
516 |
||
517 |
rotateImage |
|
518 |
||
519 |
|box rotation| |
|
520 |
box := EnterBox new. |
|
521 |
box title:'Image new rotation:'. |
|
522 |
box okText:'OK'. |
|
523 |
box abortText:'Cancel'. |
|
524 |
box initialText: '0'. |
|
525 |
box showAtPointer. |
|
526 |
(box accepted and: [(rotation := Object readFromString: box contents onError:nil) notNil]) |
|
527 |
ifTrue: |
|
528 |
[ Object errorSignal handle: |
|
529 |
[:ex| |
|
530 |
self warn: 'Image rotation failed.\' withCRs, 'An increase of image depth could help.'. |
|
531 |
] |
|
532 |
do: |
|
533 |
[ |
|
534 |
undoImage := image copy. |
|
535 |
self image: (image hardRotated: rotation) |
|
536 |
] |
|
537 |
]. |
|
538 |
! |
|
539 |
||
540 |
undo |
|
541 |
||
542 |
undoImage notNil |
|
543 |
ifTrue: |
|
544 |
[ |
|
545 |
modified := false. |
|
546 |
self image: undoImage. |
|
547 |
self invalidate |
|
548 |
] |
|
549 |
! ! |
|
550 |
||
551 |
!ImageEditView methodsFor:'image emphasis'! |
|
552 |
||
553 |
drawCursorAt: aPoint |
|
554 |
||
555 |
image isNil ifTrue: [^Cursor stop show]. |
|
556 |
((0@0 extent: image extent * magnification) containsPoint: aPoint) |
|
557 |
ifFalse:[Cursor stop show] |
|
558 |
ifTrue: [Cursor crossHair show]. |
|
559 |
||
560 |
! |
|
561 |
||
562 |
drawFrame |
|
563 |
||
564 |
self paint:Color black. |
|
565 |
self lineWidth: (magnification x//3 min: 3). |
|
566 |
self displayRectangle: ((0@0) extent:(image extent * magnification) + 2). |
|
567 |
self lineWidth:1. |
|
568 |
! |
|
569 |
||
662 | 570 |
drawFramesIn: aRectangle |
636 | 571 |
|
572 |
magnification > gridMagnification |
|
573 |
ifTrue: |
|
574 |
[ |
|
662 | 575 |
|origin lineStartingPoint lineEndingPoint oldColor| |
576 |
origin := aRectangle origin - 1. |
|
577 |
lineStartingPoint := origin + (0@magnification y). |
|
578 |
lineEndingPoint := lineStartingPoint + (aRectangle width@0). |
|
636 | 579 |
oldColor := self paint. |
580 |
self xoring: |
|
581 |
[ |
|
662 | 582 |
self displayLineFrom: lineStartingPoint to: lineEndingPoint. |
583 |
lineStartingPoint x to: lineStartingPoint x + aRectangle width - magnification x by: magnification x do: |
|
584 |
[:x| |
|
585 |
self displayLineFrom: x@(origin y) to: x@(origin y + magnification y) |
|
586 |
]. |
|
636 | 587 |
]. |
588 |
self paint: oldColor. |
|
589 |
] |
|
662 | 590 |
|
591 |
||
592 |
||
636 | 593 |
! |
594 |
||
595 |
drawLabel: aLabel |
|
596 |
||
597 |
coordInfoBlock notNil |
|
598 |
ifTrue: |
|
599 |
[ |
|
600 |
coordInfoBlock value: aLabel printString |
|
601 |
] |
|
602 |
! |
|
603 |
||
604 |
drawRectangleStartingAt: aPoint emphasis: emphasis |
|
632 | 605 |
|
633 | 606 |
|currentPoint currentExtent firstPoint lastCurrentPoint gridCorrection p| |
632 | 607 |
firstPoint := currentPoint := lastCurrentPoint := aPoint//magnification*magnification. |
636 | 608 |
magnification > gridMagnification ifFalse: [gridCorrection := 0] ifTrue: [gridCorrection := 1]. |
627 | 609 |
[Display anyButtonPressed] |
610 |
whileTrue: |
|
611 |
[ |
|
632 | 612 |
currentPoint := (0@0) max: (image extent * magnification min: (p := self translation negated + (device translatePoint: self sensor mousePoint from:device rootView id to:self id))). |
627 | 613 |
currentPoint := currentPoint//magnification*magnification. |
614 |
currentExtent := (firstPoint - currentPoint) abs. |
|
632 | 615 |
self drawCursorAt: p. |
616 |
||
627 | 617 |
currentPoint ~= lastCurrentPoint ifTrue: |
632 | 618 |
[ |
619 |
emphasis = #inverseFilledBox |
|
627 | 620 |
ifTrue: |
621 |
[ |
|
662 | 622 |
self redraw: ((firstPoint min: lastCurrentPoint) - 1 extent: (firstPoint - lastCurrentPoint) abs + 2). |
633 | 623 |
self xoring: [self fillRectangle: ((firstPoint min: currentPoint) + 1 extent: currentExtent - gridCorrection)] |
627 | 624 |
]. |
632 | 625 |
emphasis = #box |
627 | 626 |
ifTrue: |
627 |
[ |
|
662 | 628 |
|origin extent lineWidthY lineWidthX| |
629 |
origin := (firstPoint min: lastCurrentPoint) - 1. |
|
630 |
extent := (firstPoint - lastCurrentPoint) abs + 2. |
|
631 |
lineWidthY := extent y min: (magnification y + 2). |
|
632 |
lineWidthX := extent x min: (magnification x + 2). |
|
633 |
self redraw: (origin extent: (extent x@lineWidthY)). |
|
634 |
self redraw: ((origin x@(origin y + extent y - lineWidthY)) extent: (extent x@lineWidthY)). |
|
635 |
self redraw: ((origin x@(origin y + lineWidthY)) extent: (lineWidthX@(0 max: (extent y - (lineWidthY * 2))))). |
|
636 |
self redraw: (((origin x + extent x - lineWidthX)@(origin y + lineWidthY)) extent: (lineWidthX@(extent y - (lineWidthY * 2)))). |
|
627 | 637 |
self selectedColor ~= Color noColor |
638 |
ifTrue: [self paint: self selectedColor] |
|
639 |
ifFalse: [self paint: self viewBackground]. |
|
662 | 640 |
origin := (firstPoint min: currentPoint) + 1. |
641 |
extent := currentExtent - gridCorrection. |
|
642 |
lineWidthY := extent y min: magnification y. |
|
643 |
lineWidthX := extent x min: magnification x. |
|
644 |
(lineWidthY > 0) & (lineWidthX > 0) |
|
645 |
ifTrue: |
|
646 |
[ |
|
647 |
self fillRectangle: (origin extent: (extent x@lineWidthY)). |
|
648 |
self fillRectangle: ((origin x@(origin y + extent y - lineWidthY)) extent: (extent x@lineWidthY)). |
|
649 |
self fillRectangle: ((origin x@(origin y + lineWidthY)) extent: (lineWidthX@(0 max: (extent y - (lineWidthY * 2))))). |
|
650 |
self fillRectangle: (((origin x + extent x - lineWidthX)@(origin y + lineWidthY)) extent: (lineWidthX@(extent y - (lineWidthY * 2)))). |
|
651 |
] |
|
632 | 652 |
]. |
653 |
emphasis = #filledBox |
|
654 |
ifTrue: |
|
655 |
[ |
|
662 | 656 |
self redraw: ((firstPoint min: lastCurrentPoint) - 1 extent: (firstPoint - lastCurrentPoint) abs + 2). |
632 | 657 |
self selectedColor ~= Color noColor |
658 |
ifTrue: [self paint: self selectedColor] |
|
659 |
ifFalse: [self paint: self viewBackground]. |
|
633 | 660 |
self fillRectangle: ((firstPoint min: currentPoint) + 1 extent: currentExtent - gridCorrection). |
632 | 661 |
]. |
627 | 662 |
]. |
663 |
self drawLabel: currentPoint//magnification. |
|
664 |
lastCurrentPoint := currentPoint. |
|
665 |
]. |
|
632 | 666 |
Cursor normal show. |
662 | 667 |
|
668 |
^((1@1) max: (firstPoint min: currentPoint)) extent: (firstPoint - currentPoint) abs |
|
627 | 669 |
! ! |
670 |
||
671 |
!ImageEditView methodsFor:'image setting'! |
|
672 |
||
673 |
image:anImage |
|
674 |
||
675 |
(anImage isImage and: [image isNil or: [self checkModified]]) |
|
676 |
ifTrue: |
|
662 | 677 |
[ |
678 |
masterApplication notNil ifTrue: [masterApplication imagePreView image: anImage]. |
|
627 | 679 |
super image: anImage. |
680 |
^self |
|
674 | 681 |
] |
682 |
ifFalse: |
|
683 |
[ |
|
684 |
super image: nil. |
|
685 |
^nil |
|
686 |
] |
|
627 | 687 |
! |
688 |
||
689 |
loadFromFile: aFileName |
|
624 | 690 |
|
676 | 691 |
aFileName isNil ifTrue: [^nil]. |
624 | 692 |
Object errorSignal handle: |
693 |
[:exeption| |
|
674 | 694 |
modified := false. |
632 | 695 |
self warn: exeption errorString. |
624 | 696 |
^nil |
697 |
] |
|
698 |
do: |
|
676 | 699 |
[ |
700 |
|imageFromFile| |
|
701 |
(imageFromFile := Image fromFile: aFileName) notNil |
|
632 | 702 |
ifTrue: |
703 |
[ |
|
676 | 704 |
self image: imageFromFile. |
632 | 705 |
imageReaderClass := ImageReader allSubclasses |
706 |
detect: [:cls| cls isValidImageFile: aFileName] |
|
707 |
ifNone: [self error: 'Unknown image file format!!'] |
|
708 |
] |
|
709 |
ifFalse: |
|
710 |
[ |
|
711 |
self error: 'Image on file not found!!' |
|
712 |
] |
|
676 | 713 |
] |
624 | 714 |
! |
255 | 715 |
|
633 | 716 |
loadFromMessage: aMessage |
717 |
||
718 |
(self resourceMessage: aMessage) isNil |
|
719 |
ifTrue: |
|
720 |
[ |
|
721 |
^nil |
|
722 |
]. |
|
624 | 723 |
|
633 | 724 |
^self loadfromClass: resourceClass andSelector: resourceSelector |
725 |
||
726 |
||
727 |
! |
|
728 |
||
729 |
loadfromClass: aClassOrSymbol andSelector: aStringOrSymbol |
|
730 |
||
678 | 731 |
|aClass| |
732 |
||
627 | 733 |
imageReaderClass := nil. |
734 |
self resourceClass: aClassOrSymbol. |
|
735 |
self resourceSelector: aStringOrSymbol. |
|
678 | 736 |
|
737 |
((aClass := Smalltalk at: resourceClass) isClass and: |
|
738 |
[aClass class implements: resourceSelector]) |
|
624 | 739 |
ifTrue: |
740 |
[ |
|
627 | 741 |
^self image: (aClass perform: resourceSelector) copy |
674 | 742 |
] |
743 |
ifFalse: |
|
744 |
[ |
|
745 |
modified := false. |
|
746 |
^nil |
|
747 |
] |
|
748 |
||
161 | 749 |
! ! |
750 |
||
1 | 751 |
!ImageEditView methodsFor:'initialization'! |
752 |
||
161 | 753 |
initialize |
624 | 754 |
|
161 | 755 |
super initialize. |
627 | 756 |
|
161 | 757 |
magnification := 1@1. |
627 | 758 |
gridMagnification := 8@8. |
759 |
modified := false. |
|
760 |
mouseKeyColorMode := 1. |
|
761 |
resourceClass := resourceSelector := ''. |
|
762 |
selectColors := Array with: nil with: nil. |
|
1 | 763 |
! ! |
764 |
||
636 | 765 |
!ImageEditView methodsFor:'printing & storing'! |
1 | 766 |
|
636 | 767 |
loadFromInClassesOf: aSuperclassOrSymbol |
404 | 768 |
|
676 | 769 |
^self loadFromMessage: |
636 | 770 |
(ResourceSelectionBrowser |
662 | 771 |
request: 'Load Image From Class' |
636 | 772 |
onSuperclass: aSuperclassOrSymbol |
773 |
andClass: self resourceClass |
|
774 |
andSelector: self resourceSelector |
|
775 |
withResourceTypes: #(image fileImage)) |
|
776 |
||
477 | 777 |
|
161 | 778 |
! |
779 |
||
627 | 780 |
|
624 | 781 |
|
636 | 782 |
|stream| |
627 | 783 |
image isNil ifTrue: [^nil]. |
636 | 784 |
Printer supportsPostscript ifFalse: |
785 |
[ |
|
786 |
^self warn:'No postscript printer detected!!' |
|
362 | 787 |
]. |
788 |
stream := Printer newNative. |
|
636 | 789 |
stream isNil ifTrue: |
790 |
[ |
|
791 |
^self warn:'Cannot open printer stream!!'. |
|
362 | 792 |
]. |
636 | 793 |
self withWaitCursorDo: |
794 |
[ |
|
795 |
|psgc| |
|
796 |
psgc := PSGraphicsContext on:stream. |
|
627 | 797 |
psgc displayForm: (image magnifiedBy: magnification) x:0 y:0. |
398
7b7255a4db0d
show a wait cursor while printing
Claus Gittinger <cg@exept.de>
parents:
362
diff
changeset
|
798 |
psgc close. |
7b7255a4db0d
show a wait cursor while printing
Claus Gittinger <cg@exept.de>
parents:
362
diff
changeset
|
799 |
] |
624 | 800 |
! |
801 |
||
802 |
save |
|
803 |
||
632 | 804 |
self saveImageOrMask: #image. |
805 |
||
624 | 806 |
! |
807 |
||
297 | 808 |
saveAs |
809 |
"save contents into a file |
|
810 |
- ask user for filename using a fileSelectionBox." |
|
811 |
||
627 | 812 |
self saveImageFileAs |
297 | 813 |
! |
814 |
||
627 | 815 |
saveImageFileAs |
816 |
||
633 | 817 |
self saveImageFileAs: |
818 |
(FileSelectionBrowser |
|
636 | 819 |
request: 'Save Image As' |
678 | 820 |
pathName: self image fileName |
633 | 821 |
fileFilters: FileSelectionBrowser saveImageFileNameFilters) |
627 | 822 |
! |
297 | 823 |
|
627 | 824 |
saveImageFileAs: aFileName |
297 | 825 |
|
633 | 826 |
aFileName isNil ifTrue: [^nil]. |
636 | 827 |
image notNil |
627 | 828 |
ifTrue: |
829 |
[ |
|
830 |
image fileName: aFileName. |
|
632 | 831 |
self saveImageOrMask: #image |
832 |
] |
|
833 |
ifFalse: |
|
834 |
[ |
|
633 | 835 |
self warn: 'No image or file name for saving detected!!' |
632 | 836 |
] |
837 |
! |
|
838 |
||
839 |
saveImageMaskFileAs |
|
840 |
||
633 | 841 |
self saveImageMaskFileAs: |
636 | 842 |
(FileSelectionBrowser |
843 |
request: 'Save Image Mask As' |
|
678 | 844 |
pathName: self image fileName |
633 | 845 |
fileFilters: FileSelectionBrowser saveImageFileNameFilters) |
632 | 846 |
! |
847 |
||
848 |
saveImageMaskFileAs: aFileName |
|
849 |
||
633 | 850 |
aFileName isNil ifTrue: [^nil]. |
632 | 851 |
(image notNil and: [image mask notNil]) |
852 |
ifTrue: |
|
853 |
[ |
|
854 |
image mask fileName: aFileName. |
|
855 |
self saveImageOrMask: #mask |
|
627 | 856 |
] |
857 |
ifFalse: |
|
858 |
[ |
|
632 | 859 |
self warn: 'No image or image mask detected!!' |
627 | 860 |
] |
628 | 861 |
! |
862 |
||
632 | 863 |
saveImageOrMask: what |
628 | 864 |
|
632 | 865 |
Object errorSignal handle: |
866 |
[:ex| |
|
867 |
self warn: ex errorString. |
|
868 |
^nil |
|
869 |
] |
|
870 |
do: |
|
871 |
[ |
|
872 |
|fileName| |
|
873 |
image isNil ifTrue: [^self error: 'No image to save!!']. |
|
874 |
what = #image |
|
875 |
ifTrue: |
|
876 |
[ |
|
877 |
image fileName isNil ifTrue: [^self error: 'No file name for image detected!!']. |
|
878 |
fileName := image fileName asFilename |
|
879 |
]. |
|
880 |
what = #mask |
|
881 |
ifTrue: |
|
882 |
[ |
|
883 |
image mask isNil ifTrue: [^self error: 'No image mask to save!!']. |
|
884 |
image mask fileName isNil ifTrue: [^self error: 'No file name for image mask detected!!']. |
|
885 |
fileName := image mask fileName asFilename |
|
886 |
]. |
|
678 | 887 |
fileName name size = 0 ifTrue: [^self error: 'No file name detected!!']. |
632 | 888 |
(fileName suffix = 'tiff') | (fileName suffix = 'tif') ifTrue: [imageReaderClass := TIFFReader]. |
889 |
fileName suffix = 'xpm' ifTrue: [imageReaderClass := XPMReader]. |
|
890 |
fileName suffix = 'xbm' ifTrue: [imageReaderClass := XBMReader]. |
|
678 | 891 |
fileName suffix = 'gif' ifTrue: [imageReaderClass := GIFReader]. |
632 | 892 |
(fileName suffix = 'jpg') | (fileName suffix = 'jpeg') ifTrue: [imageReaderClass := JPEGReader]. |
893 |
imageReaderClass isNil ifTrue: [imageReaderClass := XPMReader. image fileName: image fileName, '.xpm']. |
|
894 |
what = #image ifTrue: [image saveOn: image fileName using: imageReaderClass. modified := false]. |
|
895 |
what = #mask ifTrue: [image mask saveOn: image mask fileName using: imageReaderClass]. |
|
678 | 896 |
] |
632 | 897 |
|
898 |
||
633 | 899 |
! |
900 |
||
901 |
saveMethod |
|
902 |
||
903 |
Object errorSignal handle: |
|
904 |
[:ex| |
|
905 |
self warn: ex errorString. |
|
906 |
^nil |
|
907 |
] |
|
908 |
do: |
|
909 |
[ |
|
910 |
|imageStoreStream cls| |
|
911 |
(self resourceSelector trimBlanks size = 0) | (cls := Smalltalk at: self resourceClass) isClass not |
|
912 |
ifTrue: [^self error: 'No class and selector for image detected!!']. |
|
913 |
self image storeOn: (imageStoreStream := WriteStream on: ''). |
|
914 |
ByteCodeCompiler |
|
915 |
compile: (self resourceSelector, |
|
916 |
'\' withCRs, ' "ImageEditor openOnClass:self andSelector:#', self resourceSelector, '"', |
|
917 |
'\\' withCRs, ' <resource: #image>\' withCRs, ' ^', imageStoreStream contents) |
|
918 |
forClass: cls class inCategory: 'resources'. |
|
919 |
modified := false. |
|
920 |
] |
|
921 |
! |
|
922 |
||
923 |
saveMethodAs |
|
924 |
||
636 | 925 |
(self resourceMessage: |
926 |
(ResourceSelectionBrowser |
|
927 |
request: 'Save On Image Resource Selector' |
|
928 |
onSuperclass: #ApplicationModel |
|
929 |
andClass: self resourceClass |
|
930 |
andSelector: self resourceSelector |
|
931 |
withResourceTypes: #(image fileImage))) notNil |
|
633 | 932 |
ifTrue: |
674 | 933 |
[ |
633 | 934 |
^self saveMethod |
674 | 935 |
]. |
633 | 936 |
^nil |
1 | 937 |
! ! |
938 |
||
161 | 939 |
!ImageEditView methodsFor:'queries'! |
5 | 940 |
|
161 | 941 |
heightOfContents |
942 |
||
943 |
image isNil ifTrue:[^ 0]. |
|
944 |
^ (image height * magnification y) rounded |
|
5 | 945 |
! |
946 |
||
627 | 947 |
imageContainsPoint: aPoint |
632 | 948 |
|
949 |
^image notNil and: |
|
950 |
[((0@0 corner:(image extent) - 1) containsPoint: (((aPoint - margin + 1) / magnification) floor))] |
|
627 | 951 |
! |
952 |
||
161 | 953 |
widthOfContents |
5 | 954 |
|
161 | 955 |
image isNil ifTrue:[^ 0]. |
956 |
^ (image width * magnification x) rounded |
|
5 | 957 |
! ! |
958 |
||
627 | 959 |
!ImageEditView methodsFor:'release'! |
960 |
||
961 |
destroy |
|
962 |
||
963 |
undoImage := nil. |
|
964 |
Clipboard := nil. |
|
965 |
super destroy. |
|
966 |
||
967 |
! ! |
|
968 |
||
632 | 969 |
!ImageEditView methodsFor:'testing'! |
970 |
||
971 |
checkModified |
|
972 |
||
973 |
modified |
|
974 |
ifTrue: |
|
975 |
[ |
|
976 |
((YesNoBox title:'Image was modified!!') |
|
977 |
noText:'Cancel'; |
|
978 |
yesText:'Waste it and proceed'; |
|
979 |
showAtPointer; |
|
980 |
accepted) ifFalse: [^false]. |
|
981 |
modified := false |
|
982 |
]. |
|
983 |
^true |
|
984 |
! ! |
|
985 |
||
255 | 986 |
!ImageEditView class methodsFor:'documentation'! |
161 | 987 |
|
988 |
version |
|
678 | 989 |
^ '$Header: /cvs/stx/stx/libwidg2/ImageEditView.st,v 1.57 1998-01-23 13:58:30 tz Exp $' |
161 | 990 |
! ! |