diff --git a/cart.odin b/cart.odin index 2585d65..9ba3090 100644 --- a/cart.odin +++ b/cart.odin @@ -29,6 +29,7 @@ loadCart :: proc(target: ^Cart, filename: cstring) -> CartLoadError { return CartLoadError.Wrong_Size } target.texture = rl.LoadTextureFromImage(target.image) + rl.SetTextureFilter(target.texture, .POINT) target.loaded = true return CartLoadError.None } diff --git a/guimode.odin b/guimode.odin index a848b7a..0d58e96 100644 --- a/guimode.odin +++ b/guimode.odin @@ -5,11 +5,12 @@ import rl "vendor:raylib" import "core:fmt" import "core:strings" import "core:slice" +import "core:bytes" import "core:os" -W :: 400 -H :: 300 +W :: 640 +H :: 480 width : int = W height : int = H @@ -23,17 +24,31 @@ fileNameBuffer : [FILENAME_MAX]byte fileNameString := cstring(&fileNameBuffer[0]) editMode := false +fileListScrolling : i32 = 0 +fileListActive : i32 = -1 +fileListFocus : i32 = -1 + +fileList : rl.FilePathList + State :: enum { CartsInput, Export, GotError, - Exported + Exported, + FileSelect } GraphicsMode :: proc() { + files = slice.into_dynamic(filesBuf[:]) cart := Cart{} target := Cart{} + fileListTarget : ^Cart + + DefaultName :string : "output.p8.png" + for char, i in DefaultName { + fileNameBuffer[i] = auto_cast char + } errorMessages := map[CartLoadError]cstring { .None = "", @@ -44,15 +59,15 @@ GraphicsMode :: proc() { defer delete(errorMessages) currentError := CartLoadError.None - rl.SetConfigFlags({rl.ConfigFlag.WINDOW_RESIZABLE}) + rl.SetConfigFlags({.WINDOW_RESIZABLE, .INTERLACED_HINT}) rl.InitWindow(W, H, "PicoRepico") rl.SetTargetFPS(60) //fontData := #load("font.ttf") //font := rl.LoadFontFromMemory(".ttf", raw_data(fontData), auto_cast len(fontData), 8, nil, 0) - font := rl.LoadFontEx("font.ttf", 32, nil, 0) - rl.GuiSetFont(font) - rl.GuiSetStyle(auto_cast rl.GuiControl.DEFAULT, auto_cast rl.GuiControlProperty.BORDER_COLOR_NORMAL, i32(rl.ColorToInt(rl.Color{211, 2, 255, 255}))) + //font := rl.LoadFontEx("font.ttf", 32, nil, 0) + //rl.GuiSetFont(font) + //rl.GuiSetStyle(auto_cast rl.GuiControl.DEFAULT, auto_cast rl.GuiControlProperty.BORDER_COLOR_NORMAL, i32(rl.ColorToInt(rl.Color{211, 2, 255, 255}))) hw : f32 = auto_cast width / 2 hh : f32 = auto_cast height / 2 @@ -67,7 +82,7 @@ GraphicsMode :: proc() { hw = auto_cast width / 2 hh = auto_cast height / 2 - #partial switch state { + switch state { case .CartsInput: { mouse := rl.GetMousePosition() if rl.IsFileDropped() { @@ -93,18 +108,24 @@ GraphicsMode :: proc() { } } + zoom = 1 + if width >= 640 && height > 450 { + zoom = 2 + } + buttonCartRect := rl.Rectangle{ - x = hw - CART_WIDTH - 20, + x = hw - CART_WIDTH * f32(zoom) - 5, y = 8, - width = CART_WIDTH, - height = CART_HEIGHT, + width = CART_WIDTH * f32(zoom), + height = CART_HEIGHT * f32(zoom), } buttonTargetRect := rl.Rectangle{ - x = hw + 20, + x = hw + 5, y = 8, - width = CART_WIDTH, - height = CART_HEIGHT, + width = CART_WIDTH * f32(zoom), + height = CART_HEIGHT * f32(zoom), } + cartRect := rl.Rectangle{0, 0, CART_WIDTH, CART_HEIGHT} convertButtonRect := rl.Rectangle{ x = hw - 40, y = auto_cast height - 38, @@ -114,20 +135,32 @@ GraphicsMode :: proc() { rl.BeginDrawing() rl.GuiDummyRec(rl.Rectangle{0, 0, auto_cast width, auto_cast height}, "") - rl.GuiButton(buttonCartRect, "Place here cart") - rl.GuiButton(buttonTargetRect, "Place here target") + if rl.GuiButton(buttonCartRect, "Drag original\ncart here") { + fileListTarget = &cart + cd(".") + state = .FileSelect + } if cart.loaded { - rl.DrawTexture(cart.texture, auto_cast buttonCartRect.x, auto_cast buttonCartRect.y, rl.WHITE) + rl.DrawTexturePro(cart.texture, cartRect, buttonCartRect, {0, 0}, 0, rl.WHITE) + } + if rl.GuiButton(buttonTargetRect, "Drag target\nshell here") { + fileListTarget = &target + cd(".") + state = .FileSelect } if target.loaded { - rl.DrawTexture(target.texture, auto_cast buttonTargetRect.x, auto_cast buttonTargetRect.y, rl.WHITE) + rl.DrawTexturePro(target.texture, cartRect, buttonTargetRect, {0, 0}, 0, rl.WHITE) } if !(cart.loaded && target.loaded) { rl.GuiDisable() } if rl.GuiButton(convertButtonRect, "CONVERT!") { state = .Export } rl.GuiEnable() + + if rl.GuiLabelButton(rl.Rectangle{auto_cast width-60, auto_cast height-20, 60, 20}, "by Nefrace") { + rl.OpenURL("https://nefrace.itch.io") + } } case .Export: { res := rl.GuiTextInputBox(rl.Rectangle{hw - 100, 60, 200, 100}, "Input filename for result", "", "ok;cancel", fileNameString, FILENAME_MAX, nil) @@ -151,8 +184,35 @@ GraphicsMode :: proc() { state = .CartsInput } } - } + case .FileSelect: { + rl.GuiPanel(rl.Rectangle{4, 4, auto_cast width - 8, auto_cast height - 8}, "Select a file") + if rl.GuiButton(rl.Rectangle{auto_cast width - 26, 8, 16, 16}, "#128#") { + state = .CartsInput + } + if rl.GuiButton(rl.Rectangle{8, 30, 50, 22}, "Open") { + if fileListActive == -1 {break} + if rl.DirectoryExists(files[fileListActive]) { + cd(files[fileListActive]) + break + } + if rl.GetFileExtension(files[fileListActive]) != ".png" { + fmt.println("not a png") + break + } + currentError = loadCart(fileListTarget, files[fileListActive]) + if currentError != .None { + state = .GotError + } + state = .CartsInput + } + if rl.GuiButton(rl.Rectangle{60, 30, 50, 22}, "Up") { + cd("..") + } + rl.GuiSetStyle(auto_cast rl.GuiControl.LISTVIEW, auto_cast rl.GuiControlProperty.TEXT_ALIGNMENT, auto_cast rl.GuiTextAlignment.TEXT_ALIGN_LEFT) + res := rl.GuiListViewEx(rl.Rectangle{8, 54, auto_cast width - 16, auto_cast height - 62}, filesPtr, auto_cast filesCount, &fileListScrolling, &fileListActive, &fileListFocus) + } + } rl.EndDrawing() } @@ -161,3 +221,41 @@ GraphicsMode :: proc() { unloadCart(&target) } +filesBuf : [1024*8]cstring +files : [dynamic]cstring +filesPtr : [^]cstring +filesCount : i32 = 0 + +cd :: proc(dir: cstring) -> (result: bool) { + result = rl.ChangeDirectory(dir) + rl.UnloadDirectoryFiles(fileList) + clear(&files) + fileList = rl.LoadDirectoryFiles(".") + + for fname in fileList.paths[:fileList.count] { + if rl.DirectoryExists(fname) || rl.GetFileExtension(fname) == ".png" { + append(&files, fname) + } + } + + slice.sort_by(files[:], proc(i,j:cstring) -> bool { + a := string(i) + b := string(j) + adir := rl.DirectoryExists(i) + bdir := rl.DirectoryExists(j) + if (adir && bdir) || (!adir && !bdir) { + return strings.compare(a, b) == -1 + } + return adir && !bdir + }) + + filesPtr = raw_data(files) + filesCount = auto_cast len(files) + + +// slice.sort_by_cmp(fileList.paths[:fileList.count], strings.compare()) + fileListScrolling = 0 + fileListActive = -1 + fileListFocus = -1 + return +}