diff --git a/hsapp/app.go b/hsapp/app.go index 624e2d22..c289ddca 100644 --- a/hsapp/app.go +++ b/hsapp/app.go @@ -219,9 +219,7 @@ func (a *App) createEditor(path *hscommon.PathEntry, state []byte, x, y, w, h fl editor.Size(w, h) - a.editorManagerMutex.Lock() a.editors = append(a.editors, editor) - a.editorManagerMutex.Unlock() editor.Show() editor.BringToFront() } @@ -244,7 +242,9 @@ func (a *App) openEditor(path *hscommon.PathEntry) { // w, h = 0, because we're creating a new editor, // width and height aren't saved, so we give 0 and // editors without AutoResize flag sets w, h to default + a.editorManagerMutex.Lock() a.createEditor(path, nil, editorWindowDefaultX, editorWindowDefaultY, 0, 0) + a.editorManagerMutex.Unlock() } func (a *App) loadProjectFromFile(file string) error { diff --git a/hsassets/images/corner_lower_south.png b/hsassets/images/corner_lower_south.png deleted file mode 100644 index d1f3b0f5..00000000 Binary files a/hsassets/images/corner_lower_south.png and /dev/null differ diff --git a/hsassets/images/corner_upper_east.png b/hsassets/images/corner_upper_east.png deleted file mode 100644 index 97371c0e..00000000 Binary files a/hsassets/images/corner_upper_east.png and /dev/null differ diff --git a/hsassets/images/corner_upper_north.png b/hsassets/images/corner_upper_north.png deleted file mode 100644 index cca7ebf5..00000000 Binary files a/hsassets/images/corner_upper_north.png and /dev/null differ diff --git a/hsassets/images/corner_upper_west.png b/hsassets/images/corner_upper_west.png deleted file mode 100644 index 089c4dda..00000000 Binary files a/hsassets/images/corner_upper_west.png and /dev/null differ diff --git a/hsassets/images/door_north.png b/hsassets/images/door_north.png deleted file mode 100644 index 5f5b0340..00000000 Binary files a/hsassets/images/door_north.png and /dev/null differ diff --git a/hsassets/images/door_west.png b/hsassets/images/door_west.png deleted file mode 100644 index b342af14..00000000 Binary files a/hsassets/images/door_west.png and /dev/null differ diff --git a/hsassets/images/floor.png b/hsassets/images/floor.png deleted file mode 100644 index fc7278ea..00000000 Binary files a/hsassets/images/floor.png and /dev/null differ diff --git a/hsassets/images/wall_north.png b/hsassets/images/wall_north.png deleted file mode 100644 index d77a70b3..00000000 Binary files a/hsassets/images/wall_north.png and /dev/null differ diff --git a/hsassets/images/wall_west.png b/hsassets/images/wall_west.png deleted file mode 100644 index 3831eba9..00000000 Binary files a/hsassets/images/wall_west.png and /dev/null differ diff --git a/hswidget/dt1widget/tile_type_image.go b/hswidget/dt1widget/tile_type_image.go index 6f4c74ed..8a7edc33 100644 --- a/hswidget/dt1widget/tile_type_image.go +++ b/hswidget/dt1widget/tile_type_image.go @@ -1,32 +1,33 @@ package dt1widget import ( + "github.com/ianling/giu" + + "github.com/OpenDiablo2/HellSpawner/hswidget/dt1widget/tiletypeimage" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" ) -func getTileTypeImage(t d2enum.TileType) string { - switch t { - case d2enum.TileFloor: - return "floor.png" - case d2enum.TileLeftWall: - return "wall_west.png" - case d2enum.TileRightWall: - return "wall_north.png" - case d2enum.TileRightPartOfNorthCornerWall: - return "corner_upper_north.png" - case d2enum.TileLeftPartOfNorthCornerWall: - return "corner_upper_west.png" - case d2enum.TileLeftEndWall: - return "corner_upper_east.png" - case d2enum.TileRightEndWall: - return "corner_lower_south.png" - case d2enum.TileSouthCornerWall: - return "corner_lower_east.png" - case d2enum.TileLeftWallWithDoor: - return "door_west.png" - case d2enum.TileRightWallWithDoor: - return "door_north.png" - default: - return "" - } +func drawTileTypeImage(t d2enum.TileType) giu.Widget { + return giu.Custom(func() { + canvas := giu.GetCanvas() + pos := giu.GetCursorScreenPos() + b := tiletypeimage.TileTypeImage(canvas, pos) + lookup := map[d2enum.TileType]func(){ + d2enum.TileFloor: func() { b.Floor() }, + d2enum.TileLeftWall: func() { b.Floor().WestWall(true) }, + d2enum.TileRightWall: func() { b.Floor().NorthWall(true) }, + d2enum.TileRightPartOfNorthCornerWall: func() { b.Floor().WestWall(false).NorthWall(true) }, + d2enum.TileLeftPartOfNorthCornerWall: func() { b.Floor().WestWall(true).NorthWall(false) }, + d2enum.TileLeftEndWall: func() { b.Floor().EastWall() }, + d2enum.TileRightEndWall: func() { b.Floor().SouthWall() }, + d2enum.TileSouthCornerWall: func() { b.Floor().Corner() }, + d2enum.TileLeftWallWithDoor: func() { b.Floor().WestDoor() }, + d2enum.TileRightWallWithDoor: func() { b.Floor().NorthDoor() }, + } + + if creator, ok := lookup[t]; ok { + creator() + } + }) } diff --git a/hswidget/dt1widget/tiletypeimage/doc.go b/hswidget/dt1widget/tiletypeimage/doc.go new file mode 100644 index 00000000..51a4ffe6 --- /dev/null +++ b/hswidget/dt1widget/tiletypeimage/doc.go @@ -0,0 +1,3 @@ +// Package tiletypeimage provides tile type image builder used for building +// a small previews of tiles. +package tiletypeimage diff --git a/hswidget/dt1widget/tiletypeimage/tile_type_image.go b/hswidget/dt1widget/tiletypeimage/tile_type_image.go new file mode 100644 index 00000000..afbd28fa --- /dev/null +++ b/hswidget/dt1widget/tiletypeimage/tile_type_image.go @@ -0,0 +1,219 @@ +package tiletypeimage + +import ( + "image" + "image/color" + + "golang.org/x/image/colornames" + + "github.com/ianling/giu" +) + +const ( + half = 2 + floorW, floorH = 60, 30 + wallW, wallH = floorW / 2, floorH + widthWallW = 10 + doorW, doorH = wallW / 2, wallH * 2 / 3 + cornerW = 20 + cornerH = int(float32(cornerW)/2*tg) * 2 + thickness = 3 + + // tg is a tangent of an angle between a floor's border and longer diagonal + tg = (float32(floorH) / half) / (float32(floorW) / half) + + // ImageW - max width of an image + ImageW = floorW + wallW + // ImageH is a max height of image + ImageH = floorH + wallH +) + +// Builder allows to build a small tile preview depending on its type +type Builder struct { + canvas *giu.Canvas + pos image.Point + borderColor, + fillingColor, + wallColor color.RGBA +} + +// TileTypeImage creates a new builder +func TileTypeImage(canvas *giu.Canvas, pos image.Point) *Builder { + return &Builder{ + canvas: canvas, + pos: pos, + borderColor: colornames.Green, + fillingColor: colornames.Yellowgreen, + wallColor: colornames.Gray, + } +} + +// Floor adds a floor preview +func (b *Builder) Floor() *Builder { + pos := b.pos.Add(image.Pt(floorW/half, wallH)) + p1 := pos.Add(image.Pt(0, 0)) + p2 := pos.Add(image.Pt(floorW/half, floorH/half)) + p3 := pos.Add(image.Pt(0, floorH)) + p4 := pos.Add(image.Pt(-floorW/half, floorH/half)) + + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + b.canvas.AddQuadFilled(p1, p2, p3, p4, b.fillingColor) + + return b +} + +// WestWall adds a west wall +func (b *Builder) WestWall(filling bool) *Builder { + p3 := b.pos.Add(image.Pt(wallW, wallH)) + p4 := b.pos.Add(image.Pt(0, wallH+floorH/half)) + p1 := p4.Add(image.Pt(0, -wallH)) + p2 := p3.Add(image.Pt(0, -wallH)) + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + + if filling { + b.canvas.AddQuadFilled(p1, p2, p3, p4, b.wallColor) + } + + return b +} + +// NorthWall adds a north (right) wall +func (b *Builder) NorthWall(filling bool) *Builder { + pos := b.pos.Add(image.Pt(wallW, 0)) + p3 := pos.Add(image.Pt(wallW, wallH+floorH/half)) + p4 := pos.Add(image.Pt(0, wallH)) + p1 := p4.Add(image.Pt(0, -wallH)) + p2 := p3.Add(image.Pt(0, -wallH)) + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + + if filling { + b.canvas.AddQuadFilled(p1, p2, p3, p4, b.wallColor) + } + + return b +} + +// EastWall adds an easter wall +func (b *Builder) EastWall() *Builder { + pos := b.pos.Add(image.Pt(wallW, 0)) + my := float32(floorH/half) / float32(floorW/half) * float32(widthWallW) + p3 := pos.Add(image.Pt(wallW, wallH+floorH/half)) + p4 := pos.Add(image.Pt(-widthWallW, wallH-int(my))) + p1 := p4.Add(image.Pt(0, -wallH)) + p2 := p3.Add(image.Pt(0, -wallH)) + + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + b.canvas.AddQuadFilled(p1, p2, p3, p4, b.wallColor) + + return b +} + +// SouthWall adds a wall on a south +func (b *Builder) SouthWall() *Builder { + my := float32(floorH/half) / float32(floorW/half) * float32(widthWallW) + p3 := b.pos.Add(image.Pt(wallW+widthWallW, wallH-int(my))) + p4 := b.pos.Add(image.Pt(0, wallH+floorH/half)) + p1 := p4.Add(image.Pt(0, -wallH)) + p2 := p3.Add(image.Pt(0, -wallH)) + + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + b.canvas.AddQuadFilled(p1, p2, p3, p4, b.wallColor) + + return b +} + +// WestDoor builds wall with a doors on a west edge +func (b *Builder) WestDoor() *Builder { + p3 := b.pos.Add(image.Pt(wallW, wallH)) + p4 := b.pos.Add(image.Pt(0, wallH+floorH/half)) + p1 := p4.Add(image.Pt(0, -wallH)) + p2 := p3.Add(image.Pt(0, -wallH)) + + // bottom of the doors + w := (wallW-doorW)/half + doorW + mod := float32((wallW-doorW)/half) * tg + h := wallH - (floorH / half) + mod + d3 := b.pos.Add(image.Pt(w, int(h)+floorH/half)) + + w = (wallW - doorW) / half + mod = float32((wallW-doorW)/half+doorW) * tg + h = wallH - (floorH / half) + mod + d4 := b.pos.Add(image.Pt(w, int(h)+floorH/half)) + + d1 := d4.Add(image.Pt(0, -doorH)) + d2 := d3.Add(image.Pt(0, -doorH)) + + // wall border + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + // door border + b.canvas.AddQuad(d1, d2, d3, d4, b.borderColor, thickness) + // wall filling + b.canvas.AddQuadFilled(p1, p2, d2, d1, b.wallColor) + b.canvas.AddQuadFilled(p2, p3, d3, d2, b.wallColor) + b.canvas.AddQuadFilled(p3, p4, d4, d3, b.wallColor) + b.canvas.AddQuadFilled(p4, p1, d1, d4, b.wallColor) + + return b +} + +// NorthDoor builds a wall with a doors on north edge +func (b *Builder) NorthDoor() *Builder { + pos := b.pos.Add(image.Pt(wallW, 0)) + p3 := pos.Add(image.Pt(wallW, wallH+floorH/half)) + p4 := pos.Add(image.Pt(0, wallH)) + p1 := p4.Add(image.Pt(0, -wallH)) + p2 := p3.Add(image.Pt(0, -wallH)) + + // bottom of the doors + w := (wallW-doorW)/half + doorW + mod := float32((wallW+doorW)/half) * tg + h := wallH - (floorH / half) + mod + d3 := pos.Add(image.Pt(w, int(h)+floorH/half)) + + w = (wallW - doorW) / half + mod = float32((wallW-doorW)/half) * tg + h = wallH - (floorH / half) + mod + d4 := pos.Add(image.Pt(w, int(h)+floorH/half)) + + d1 := d4.Add(image.Pt(0, -doorH)) + d2 := d3.Add(image.Pt(0, -doorH)) + + // wall border + b.canvas.AddQuad(p1, p2, p3, p4, b.borderColor, thickness) + // door border + b.canvas.AddQuad(d1, d2, d3, d4, b.borderColor, thickness) + // wall filling + b.canvas.AddQuadFilled(p1, p2, d2, d1, b.wallColor) + b.canvas.AddQuadFilled(p2, p3, d3, d2, b.wallColor) + b.canvas.AddQuadFilled(p3, p4, d4, d3, b.wallColor) + b.canvas.AddQuadFilled(p4, p1, d1, d4, b.wallColor) + + return b +} + +// Corner draws a "lower-right" corner +func (b *Builder) Corner() *Builder { + padding := (floorW - cornerW) / half + pos := b.pos + + b1 := pos.Add(image.Pt(padding, wallH+cornerH/2)) + b2 := pos.Add(image.Pt(floorW/half, wallH+cornerH)) + b3 := pos.Add(image.Pt(padding+cornerW, wallH+cornerH/2)) + + u1 := b1.Add(image.Pt(0, -wallH)) + u2 := b2.Add(image.Pt(0, -wallH)) + u3 := b3.Add(image.Pt(0, -wallH)) + u4 := u2.Add(image.Pt(0, -cornerH)) + + // borders + b.canvas.AddQuad(u1, u2, b2, b1, b.borderColor, thickness) + b.canvas.AddQuad(u2, u3, b3, b2, b.borderColor, thickness) + b.canvas.AddQuad(u1, u2, u3, u4, b.borderColor, thickness) + + // filling + b.canvas.AddQuadFilled(u1, u2.Add(image.Pt(-1, 0)), b2.Add(image.Pt(-1, 0)), b1, b.wallColor) + b.canvas.AddQuadFilled(u2.Add(image.Pt(1, 0)), u3, b3, b2.Add(image.Pt(1, 0)), b.wallColor) + b.canvas.AddQuadFilled(u1.Add(image.Pt(1, 0)), u2.Add(image.Pt(0, -1)), u3.Add(image.Pt(-1, 0)), u4, b.wallColor) + + return b +} diff --git a/hswidget/dt1widget/widget.go b/hswidget/dt1widget/widget.go index a6b7bdf0..0b73a4be 100644 --- a/hswidget/dt1widget/widget.go +++ b/hswidget/dt1widget/widget.go @@ -19,6 +19,7 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math" "github.com/OpenDiablo2/HellSpawner/hscommon" + "github.com/OpenDiablo2/HellSpawner/hswidget/dt1widget/tiletypeimage" ) const ( @@ -34,7 +35,6 @@ const ( subtileWidth = gridMaxWidth / gridDivisionsXY halfTileW = subtileWidth >> 1 halfTileH = subtileHeight >> 1 - imageW, imageH = 32, 32 ) type tileIdentity string @@ -435,8 +435,6 @@ func (p *widget) makeTileDisplay(state *widgetState, tile *d2dt1.Tile) *giu.Layo } func (p *widget) makeTileInfoTab(tile *d2dt1.Tile) giu.Layout { - var tileTypeImage *giu.ImageWithFileWidget - // we're creating list of tile names tileTypeList := make([]string, d2enum.TileRightWallWithDoor+1) for i := d2enum.TileFloor; i <= d2enum.TileRightWallWithDoor; i++ { @@ -457,10 +455,6 @@ func (p *widget) makeTileInfoTab(tile *d2dt1.Tile) giu.Layout { tileTypeIdx = int32(len(tileTypeList) - 1) } - tileImageFile := getTileTypeImage(d2enum.TileType(tile.Type)) - - tileTypeImage = giu.ImageWithFile("./hsassets/images/" + tileImageFile) - tileTypeInfo := giu.Layout{ giu.Row( giu.Label("Type: "), @@ -469,12 +463,6 @@ func (p *widget) makeTileInfoTab(tile *d2dt1.Tile) giu.Layout { ), } - if tileTypeImage != nil { - tileTypeInfo = append(tileTypeInfo, - tileTypeImage.Size(imageW, imageH), - ) - } - w, h := tile.Width, tile.Height if h < 0 { h *= -1 @@ -516,7 +504,8 @@ func (p *widget) makeTileInfoTab(tile *d2dt1.Tile) giu.Layout { spacer, tileTypeInfo, - spacer, + drawTileTypeImage(d2enum.TileType(tile.Type)), + giu.Dummy(1, tiletypeimage.ImageH), giu.Row( giu.Label("Style:"),