Skip to content

Commit c7351fe

Browse files
authored
outline selection fix, image preview, image editor (#534)
1 parent 0dea579 commit c7351fe

File tree

3 files changed

+95
-12
lines changed

3 files changed

+95
-12
lines changed

nimx/image_preview.nim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import std/math
2+
import ./assets/asset_loading
23
import ./[font, image, button, view, event, context, types, layout, app, view_event_handling, clip_view]
34

45
const titleSize = 20.0
@@ -87,6 +88,11 @@ method onScroll*(v: ImagePreview, e: var Event): bool =
8788
v.scaleOverride = clamp(v.scaleOverride + (e.offset.y / 300.0), 0.1, 10.0)
8889
result = true
8990

91+
proc loadImage*(v: ImagePreview, path: string, cb: proc() {.gcsafe.}) =
92+
loadAsset[Image]("file://" & path) do(i: Image, err: string):
93+
v.image = i
94+
cb()
95+
9096
proc addOriginConstraints(w: Window, v: View, desiredOrigin: Point) =
9197
let w = mainApplication().keyWindow
9298
var wp = desiredOrigin

nimx/outline_view.nim

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,12 @@ proc drawDisclosureTriangle(ctx: GraphicsContext, disclosed: bool, r: Rect) =
8282
method draw*(c: OutlineCell, r: Rect) =
8383
procCall c.TableViewCell.draw(r)
8484
let ctx = currentContext()
85-
if c.selected:
86-
ctx.fillColor = newColor(1, 1, 1)
87-
else:
88-
ctx.fillColor = newColor(0.1, 0.1, 0.1)
89-
ctx.drawDisclosureTriangle(c.mItem.expanded, c.disclosureTriangleRect)
85+
if c.mItem.children.len > 0:
86+
if c.selected:
87+
ctx.fillColor = newColor(1, 1, 1)
88+
else:
89+
ctx.fillColor = newColor(0.1, 0.1, 0.1)
90+
ctx.drawDisclosureTriangle(c.mItem.expanded, c.disclosureTriangleRect)
9091

9192
# TODO: revice
9293
if c.outlineView.dropInsideItem != nil and c.outlineView.dropInsideItem.cell == c:
@@ -340,7 +341,11 @@ proc scrollToSelection*(v: OutlineView) =
340341
proc selectItemAtIndexPath*(v: OutlineView, ip: seq[int], scroll: bool = true) =
341342
if ip.len > 1:
342343
v.expandBranch(ip[0..^2])
344+
v.clearSelection()
343345
v.selectedIndexPath = ip
346+
let selected = v.selectedNode()
347+
if not selected.isNil and not selected.cell.isNil:
348+
selected.cell.selected = true
344349
v.selectionChanged()
345350
if scroll:
346351
v.scrollToSelection()
@@ -355,6 +360,7 @@ proc isSubpathOfPath(subpath, path: openarray[int]): bool =
355360

356361
method onTouchEv*(v: OutlineView, e: var Event): bool =
357362
result = procCall v.TableView.onTouchEv(e)
363+
discard v.makeFirstResponder()
358364

359365
if e.buttonState == bsUp:
360366
let pos = e.localPosition

nimx/property_editors/standard_editors.nim

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,44 @@ import std/[strutils, tables, algorithm]
22

33
import ../[ view, text_field, matrixes, image, button, color_picker,
44
context, portable_gl, layout, popup_button, font, property_visitor,
5-
numeric_text_field, system_logger, image_preview ]
6-
5+
numeric_text_field, system_logger, image_preview, drag_and_drop,
6+
render_to_image
7+
]
8+
import ../pasteboard/pasteboard_item
9+
import ../assets/asset_loading
710
import ./propedit_registry
811
import variant
912

13+
1014
when defined(js):
1115
from dom import alert, window
1216
elif not defined(android) and not defined(ios):
1317
import os_files/dialog
1418

19+
type
20+
NimxImageEditorDropDelegate* = ref object of DragDestinationDelegate
21+
callback: proc(i: Image) {.gcsafe.}
22+
23+
const nimxPbImage* = "nimx.pb.image"
24+
25+
method onDragEnter*(dd: NimxImageEditorDropDelegate, target: View, i: PasteboardItem) =
26+
if i.kind == nimxPbImage:
27+
target.backgroundColor.a = 0.5
28+
29+
method onDragExit*(dd: NimxImageEditorDropDelegate, target: View, i: PasteboardItem) =
30+
if i.kind == nimxPbImage:
31+
target.backgroundColor.a = 0.0
32+
33+
method onDrop*(dd: NimxImageEditorDropDelegate, target: View, i: PasteboardItem) =
34+
target.backgroundColor.a = 0.0
35+
if i.kind == nimxPbImage:
36+
loadAsset[Image]("file://" & i.data) do(image: Image, err: string):
37+
if image.isNil:
38+
echo "Can't load image from ", i.data
39+
return
40+
if not dd.callback.isNil:
41+
dd.callback(image)
42+
1543
template toStr(v: SomeFloat, precision: uint): string = formatFloat(v, ffDecimal, precision)
1644
template toStr(v: SomeInteger): string = $v
1745

@@ -397,26 +425,60 @@ proc newFontPropertyView(setter: proc(s: Font) {.gcsafe.}, getter: proc(): Font
397425
result = r
398426

399427
when not defined(android) and not defined(ios):
428+
429+
type
430+
ButtonImageView = ref object of Button
431+
originalImage: Image
432+
433+
proc `onImageDropped=`(v: ButtonImageView, cb: proc(i: Image){.gcsafe.}) =
434+
v.dragDestination.NimxImageEditorDropDelegate.callback = cb
435+
436+
method init*(v: ButtonImageView) =
437+
procCall v.Button.init()
438+
v.hasBezel = false
439+
v.dragDestination = new(NimxImageEditorDropDelegate)
440+
441+
method draw*(v: ButtonImageView, r:Rect) =
442+
let c = currentContext()
443+
c.fillColor = v.backgroundColor
444+
c.drawRect(r)
445+
446+
if v.originalImage.isNil: return
447+
if v.image.isNil and v.originalImage.size.width > v.frame.width or v.originalImage.size.height > v.frame.height:
448+
let imageSize = min(v.frame.width, v.frame.height)
449+
let scale = imageSize / max(v.originalImage.size.width, v.originalImage.size.height)
450+
let img = imageWithSize(newSize(imageSize, imageSize))
451+
img.draw:
452+
c.drawImage(v.originalImage, newRect(1, 1, v.originalImage.size.width * scale - 1, v.originalImage.size.height * scale - 1))
453+
v.image = img
454+
else:
455+
v.image = v.originalImage
456+
457+
const offset = 2
458+
c.drawImage(v.image, newRect(r.x + offset, r.y + offset, r.width - offset*2, r.height - offset*2))
459+
400460
proc newImagePropertyView(setter: proc(s: Image) {.gcsafe.}, getter: proc(): Image {.gcsafe.}): PropertyEditorView =
401461
var loadedImage = getter()
462+
proc imageDropped(i: Image) {.gcsafe.}
402463
let r = new(PropertyEditorView)
403464
r.makeLayout:
404-
- Button as imagePlac:
465+
- ButtonImageView as imagePlac:
405466
top == super
406467
leading == super
407468
width == 128
408469
height == 128
409470
hasBezel: false
410-
image: loadedImage
411471
backgroundColor: newColor(0.222, 0.444, 0.666)
472+
originalImage: loadedImage
412473
onAction:
413474
if imagePlac.image.isNil:
414475
return
415476

416477
var imagePreview = new(ImagePreview)
417-
imagePreview.image = imagePlac.image
478+
imagePreview.image = imagePlac.originalImage
418479
imagePreview.popupAtCenterOfWindow()
419-
480+
onImageDropped do(i: Image):
481+
imageDropped(i)
420482
- View:
421483
top == super
422484
bottom == super
@@ -464,7 +526,8 @@ when not defined(android) and not defined(ios):
464526
var i: Image
465527
try:
466528
i = imageWithContentsOfFile(path)
467-
imagePlac.image = i
529+
imagePlac.originalImage = i
530+
imagePlac.image = nil
468531
widthLabel.text = "w:" & $i.size.width
469532
heightLabel.text = "h:" & $i.size.height
470533
except:
@@ -474,10 +537,18 @@ when not defined(android) and not defined(ios):
474537
# if not pv.changeInspector.isNil:
475538
# pv.changeInspector()
476539

540+
proc imageDropped(i: Image) {.gcsafe.} =
541+
imagePlac.originalImage = i
542+
imagePlac.image = nil
543+
widthLabel.text = "w:" & $i.size.width
544+
heightLabel.text = "h:" & $i.size.height
545+
setter(i)
546+
477547
if not loadedImage.isNil:
478548
widthLabel.text = "w:" & $loadedImage.size.width
479549
heightLabel.text = "h:" & $loadedImage.size.height
480550
result = r
551+
481552
registerPropertyEditor(newImagePropertyView)
482553

483554
registerPropertyEditor(newTextPropertyView)

0 commit comments

Comments
 (0)