• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Martomate / TriPaint / 9275511596

28 May 2024 07:51PM UTC coverage: 29.682% (+1.8%) from 27.877%
9275511596

push

github

Martomate
Updated to Scala 3.4 and MUnit 1.0

2 of 11 new or added lines in 9 files covered. (18.18%)

430 existing lines in 38 files now uncovered.

401 of 1351 relevant lines covered (29.68%)

0.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.42
/src/main/scala/tripaint/model/ImageGrid.scala
1
package tripaint.model
2

3
import tripaint.infrastructure.FileSystem
4
import tripaint.model.coords.{GridCoords, PixelCoords}
5
import tripaint.model.image.{
6
  GridCell,
7
  ImagePool,
8
  ImageSaveCollisionHandler,
9
  ImageStorage,
10
  RegularImage
11
}
12
import tripaint.model.image.ImagePool.{SaveInfo, SaveLocation}
13
import tripaint.util.{EventDispatcher, Tracker}
14

15
import scala.collection.mutable
16
import scala.collection.mutable.ArrayBuffer
17

18
object ImageGrid {
19
  enum Event:
20
    case ImageAdded(image: GridCell)
21
    case ImageRemoved(image: GridCell)
22
    case PixelChanged(coords: PixelCoords, from: Color, to: Color)
23
    case ImageChangedALot(coords: GridCoords)
24

25
  def fromCells(imageSize: Int, cells: Seq[GridCell]): ImageGrid =
×
26
    val grid = new ImageGrid(imageSize)
×
UNCOV
27
    for c <- cells do grid.set(c)
×
28
    grid
29
}
30

31
class ImageGrid(init_imageSize: Int) {
32
  private var _imageSize: Int = init_imageSize
33
  def imageSize: Int = _imageSize
1✔
34

35
  private val _images: ArrayBuffer[GridCell] = ArrayBuffer.empty
1✔
36
  def images: Seq[GridCell] = _images.toSeq
1✔
37

38
  private val imageTrackerRevokeFns = mutable.Map.empty[GridCoords, Tracker.RevokeFn]
1✔
39

40
  private val dispatcher = new EventDispatcher[ImageGrid.Event]
1✔
41
  def trackChanges(tracker: Tracker[ImageGrid.Event]): Unit = dispatcher.track(tracker)
1✔
42

43
  def apply(coords: GridCoords): Option[GridCell] = _images.find(_.coords == coords)
1✔
44

UNCOV
45
  def findByStorage(storage: ImageStorage): Option[GridCell] = images.find(_.storage == storage)
×
46

47
  def set(image: GridCell): Unit = {
1✔
48
    val idx = _images.indexWhere(_.coords == image.coords)
1✔
49
    if (idx != -1) {
1✔
50
      val prev = _images(idx)
1✔
UNCOV
51
      if (prev == image) {
×
52
        return
53
      }
1✔
54
      imageTrackerRevokeFns.remove(image.coords).foreach(_.apply())
1✔
55
      dispatcher.notify(ImageGrid.Event.ImageRemoved(prev))
1✔
56
      _images(idx) = image
1✔
57
    } else _images += image
1✔
58
    imageTrackerRevokeFns += image.coords -> image.trackChanges(e =>
1✔
59
      this.onGridCellEvent(image.coords, e)
1✔
60
    )
61
    dispatcher.notify(ImageGrid.Event.ImageAdded(image))
1✔
62
  }
63

64
  def -=(coords: GridCoords): GridCell = {
1✔
65
    val idx = _images.indexWhere(_.coords == coords)
1✔
66
    if (idx != -1) {
1✔
67
      val ret = _images.remove(idx)
1✔
68
      imageTrackerRevokeFns.remove(ret.coords).foreach(_.apply())
1✔
69
      dispatcher.notify(ImageGrid.Event.ImageRemoved(ret))
1✔
70
      ret
71
    } else null
1✔
72
  }
73

74
  private val undoManager = new UndoManager
1✔
75

76
  def performChange(change: ImageGridChange): Unit =
1✔
77
    change.redo()
1✔
78
    undoManager.append(change)
1✔
79
    for im <- images do im.onImageChangedALot()
1✔
80

81
  def undo(): Unit =
1✔
82
    undoManager.undo()
1✔
83
    for im <- images do im.onImageChangedALot()
1✔
84

85
  def redo(): Unit =
×
86
    undoManager.redo()
×
UNCOV
87
    for im <- images do im.onImageChangedALot()
×
88

89
  def setImageSizeIfEmpty(size: Int): Boolean = {
1✔
90
    if (_images.isEmpty) {
1✔
91
      _imageSize = size
92
      true
93
    } else false
1✔
94
  }
95

96
  def setImageSource(image: ImageStorage, location: SaveLocation, info: SaveInfo)(
1✔
97
      imagePool: ImagePool,
98
      imageSaveCollisionHandler: ImageSaveCollisionHandler
99
  ): Boolean =
100
    imagePool.imageAt(location) match
1✔
101
      case Some(currentImage) =>
1✔
102
        if currentImage == image then
103
          imagePool.set(image, location, info)
1✔
104
          true
105
        else
106
          imageSaveCollisionHandler.shouldReplaceImage(currentImage, image, location) match
1✔
107
            case Some(true) =>
108
              imagePool.set(image, location, info)
1✔
109
              this._images.find(_.storage == currentImage).foreach(_.replaceImage(image))
1✔
110
              true
111
            case Some(false) =>
112
              imagePool.remove(image)
1✔
113
              imagePool.set(currentImage, location, info)
1✔
UNCOV
114
              this._images.find(_.storage == image).foreach(_.replaceImage(currentImage))
×
115
              true
116
            case None =>
1✔
117
              false
118
      case None =>
119
        imagePool.set(image, location, info)
1✔
120
        true
121

122
  def save(
1✔
123
      image: ImageStorage,
124
      fileSystem: FileSystem,
125
      loc: SaveLocation,
126
      info: SaveInfo
127
  ): Boolean =
128
    val didWrite = doSave(image, fileSystem, loc, info)
1✔
129

130
    if didWrite then
131
      for
1✔
132
        im <- this._images
1✔
133
        if im.storage == image
1✔
134
      do im.setImageSaved()
1✔
135
    didWrite
136

137
  private def doSave(
1✔
138
      image: ImageStorage,
139
      fileSystem: FileSystem,
140
      loc: SaveLocation,
141
      info: SaveInfo
142
  ): Boolean =
143
    val oldImage = fileSystem.readImage(loc.file)
1✔
144

145
    val imageToSave = image.toRegularImage(info.format)
1✔
146
    val newImage = RegularImage.fromBaseAndOverlay(oldImage, imageToSave, loc.offset)
1✔
147

148
    fileSystem.writeImage(newImage, loc.file)
1✔
149

150
  def replaceImage(coords: GridCoords, newImage: ImageStorage): Unit =
×
UNCOV
151
    apply(coords).foreach(_.replaceImage(newImage))
×
152

153
  final def selectedImages: Seq[GridCell] = images.filter(_.editable)
1✔
154

UNCOV
155
  final def changedImages: Seq[GridCell] = images.filter(_.changed)
×
156

157
  private def onGridCellEvent(cell: GridCoords, event: GridCell.Event): Unit = {
1✔
158
    event match {
159
      case GridCell.Event.PixelChanged(pix, from, to) =>
1✔
160
        dispatcher.notify(ImageGrid.Event.PixelChanged(PixelCoords(cell, pix), from, to))
1✔
161
      case GridCell.Event.ImageChangedALot =>
1✔
162
        dispatcher.notify(ImageGrid.Event.ImageChangedALot(cell))
1✔
163
    }
164
  }
165
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc