Compare commits
76 Commits
v0.2
...
raylib-exp
| Author | SHA1 | Date | |
|---|---|---|---|
| 50105c242a | |||
| 6e8d97f29b | |||
| c8e0f08aae | |||
| 916f9cc79b | |||
| e4e5adaf13 | |||
| 7a2ebd533e | |||
| 2f0ca5418c | |||
| ce9d4aed23 | |||
| 712a5ab33d | |||
| 6723f933b4 | |||
| 016fc35745 | |||
| ba5e3510ec | |||
| 7e2d7ee14b | |||
| b20de4f1d6 | |||
| d2e91baa6b | |||
| a0f22e480b | |||
| 57f921c2cb | |||
| 55f897db46 | |||
| 3d9583281e | |||
| ec4d66f6b2 | |||
| c442ef5688 | |||
| 78d3723bf4 | |||
| 828b9f4cda | |||
| be64aa083f | |||
| 3111705cae | |||
| 868ae8f700 | |||
| 226e9d6210 | |||
| 56748f043e | |||
| 3d3239fe0a | |||
| 6e643b68ac | |||
| 539f33d25e | |||
| 4d3cb9f486 | |||
| a55c82483a | |||
| 9e9bb82025 | |||
| ea91d3cd80 | |||
| 2a0d53db09 | |||
| a0213d1886 | |||
| 695ce815d9 | |||
| 01556c1eb0 | |||
| d7410bb88f | |||
| bc63e6d10f | |||
| 0403825c3d | |||
| 0f1bb3fabd | |||
| 78c6842fab | |||
| dc1edbad3a | |||
| 6dd00c5f8f | |||
| e68337886f | |||
| 3b639f53fd | |||
| 3199ad88fd | |||
| a221d18d33 | |||
| a9eeb3bb1c | |||
| 844a282fd7 | |||
| 9da352a315 | |||
| 34b8f7c926 | |||
| 5d5cedec58 | |||
| 8441a8b752 | |||
| d64d88e0a5 | |||
| 5eeb9cc702 | |||
| fc3411e568 | |||
| 77ce9e8ad4 | |||
| 63dd8ebb83 | |||
| 7cf45c9ac8 | |||
| 2f8de0bed2 | |||
| 67ca030bb2 | |||
| da46399ded | |||
| e5d0b6a9a2 | |||
| f4ca2115d4 | |||
| 0cc7f8f445 | |||
| 767e894acd | |||
| 06e2afef1d | |||
| f614c14013 | |||
| 998c07b90b | |||
| 3d44c82e65 | |||
| 08a453b5d5 | |||
| be42963441 | |||
| 50ad374124 |
@@ -0,0 +1 @@
|
||||
testing/
|
||||
@@ -1,33 +1,51 @@
|
||||
# LinuxPA
|
||||
The goal is to create a fully functional PortableApps.com type launcher that can properly parse data from the PortableApps.com format. Apps are launched by a .sh file in the app's directory. Currently pulls out the Name and Category from App/AppInfo/appinfo.ini
|
||||
Works well with AppImage apps.
|
||||
|
||||
# Why?
|
||||
I know that Linux only has about 2% desktop usage and I know that the traditional way to install apps isn't portable, but over the past year or so I've started to put linux apps on my flash drive (AppImage is a great example of a portable solution to linux apps. Also a lot of DRM-free games can be run portably), but there was no easy way to organize my linux apps, so I created one. I personally have used the PortableApps.com launcher for years now and I love how properly formated the apps are, which allows me to grab info about the app easily.
|
||||
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
|
||||
|
||||
# Why script files?
|
||||
In general linux executable files have no extensions and can be a pain when trying to figure out what is executable and what isn't. I figured script files are easy to detect and allow a large amount of flexibility for me (and others who want to make apps work with this launcher). See below for .AppImage support (Get AppImages from [here](https://bintray.com/probono/AppImages))
|
||||
## How to use
|
||||
|
||||
# Why Go?
|
||||
Because I like Go :) Also the way it includes all it needs into one friendly executable.
|
||||
Just double click on an app to launch it! If there are multiple executables, you can either select the specific executable, or if you just double click the app it'll launch the first linux executable it finds. .sh script files have priority over other executable files.
|
||||
|
||||
# What is needed?
|
||||
Basically you need go to compile the source, AND YOU ALSO NEED TO MOUNT YOUR FLASH DRIVE SO YOU CAN EXECUTE FILES ON IT!!!! I've found that the mount arguments of `exec,noauto,nodev,nosuid,umask=0000` works well (I personally put my flash drive into /etc/fstab).
|
||||
## Apps
|
||||
|
||||
# Format
|
||||
The first place the program looks for an app's icon and info is in the /App/AppInfo directory (icon defaults to appicon_32.png, otherwise it just picks the last one it finds), but if it can't find the appinfo.ini or app icon, it looks in the apps root directory for appinfo.ini and appicon.png for info and icon respectively(Just to make it easier for custom settings in an app).
|
||||
The below place provides linux executables that don't need libs installed on the host system:
|
||||
[https://appimage.github.io/](https://appimage.github.io/)
|
||||
|
||||
# common.sh
|
||||
common.sh is run before any program so you can set environment variables (such as HOME). common.sh should be in PortableApps/LinuxPACom folder.
|
||||
## PortableApps.com Compatibility
|
||||
|
||||
# AppImage support
|
||||
It will now launch .AppImage files! If a .sh script and an .AppImage executable are both in a directory, the .sh script takes precedence. You can get AppImages from [here](https://bintray.com/probono/AppImages).
|
||||
LinuxPA works will with the PortableApps.com launcher, as it looks for apps in the PortableApps folder and grabs the app's name and icon from where it should be in the PortableApps.com format.
|
||||
My forum at PortableApps.com can be found [here](http://portableapps.com/node/54998).
|
||||
|
||||
## common.sh
|
||||
|
||||
common.sh is found in the PortableApps/LinuxPACom folder and is executed before the app. I mainly use it to set environment variables (such as HOME). You can create and edit the common.sh from settings.
|
||||
|
||||
## Simple App Setup
|
||||
|
||||
Because apps aren't natively formated in the PortableApps.com format, LinuxPA will look in the root directory for a AppInfo.ini (for basic info such as category and name) and appicon.png. If they aren't found, it looks where the appicon_\*.png and AppInfo.ini is in PortableApps format. You can set what the AppInfo.ini and appicon.png are from LinuxPA.
|
||||
|
||||
## AppImage Support
|
||||
|
||||
[AppImage Website](http://appimage.org)
|
||||
I'm looking into improving AppImage support. As of 2.1.5.0 IF `unsquashfs` is in $PATH then some advanced AppImage support is available and it will automagically get the name and possibly the icon of it. I'm looking into better support, but it might be a while.
|
||||
|
||||
## USB mount
|
||||
|
||||
Unfortunately Linux, by default, doesn't support running executables off of FAT formated flash drives, requiring you to mount your drive with special mount arguments or format in a linux friendly format (such as EXT4). I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
|
||||
|
||||
## Screenshots
|
||||
|
||||
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6). The screenshots are with the adapta gtk theme
|
||||
|
||||
## TODO (Might be in order)
|
||||
|
||||
# TODO (Might be in order)
|
||||
1. MAKE IT BETTER
|
||||
1. Improve linux executable detection (A.K.A. a pain in the butt)
|
||||
1. Launching of .exe files via wine (wine will have to be installed on the host system, unless there is some portable wine, I may have found one)
|
||||
1. Add settings menu
|
||||
1. Add updater for .AppImage files
|
||||
1. Download .AppImage files (maybe)
|
||||
1. Check if all apps are closed when it closes and ask if you want to force stop the apps.
|
||||
1. Integrate [goappimage](https://github.com/probonod/go-appimage) library for better AppImage integration.
|
||||
1. Try to `chmod +x` executables if they don't have the permission
|
||||
1. Manual update check
|
||||
1. Better AppImage integrations (Specifically updating and better appimage downloading)
|
||||
1. Get information (such as name and icon) directly from an appimage
|
||||
1. Better appimage downloading (probably based around [AppImageHub](https://appimage.github.io/apps/))
|
||||
1. Sandboxing support
|
||||
1. Might be possible by packaging as an AppImage and providing Firejail, or simply just downloading it (like with Wine)
|
||||
1. Check if all apps are closed when it closes and ask if you want to force stop the apps
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
module github.com/CalebQ42/LinuxPA
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b
|
||||
|
||||
require (
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b h1:JJfspevP3YOXcSKVABizYOv++yMpTJIdPUtoDzF/RWw=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
@@ -0,0 +1,260 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
// A rectangle with borders.
|
||||
// Default only has black borders.
|
||||
type Rect struct {
|
||||
x int32
|
||||
y int32
|
||||
h int32
|
||||
w int32
|
||||
radius int32
|
||||
reload bool
|
||||
shown bool
|
||||
rendering bool
|
||||
|
||||
borderWidth int32
|
||||
borderColor color.RGBA
|
||||
fillColor color.RGBA
|
||||
|
||||
curTweens map[string]*Tween
|
||||
tex rl.RenderTexture2D
|
||||
}
|
||||
|
||||
func NewRect(x, y, height, width int32) *Rect {
|
||||
r := &Rect{
|
||||
x: x,
|
||||
y: y,
|
||||
h: height,
|
||||
w: width,
|
||||
radius: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: rl.Black,
|
||||
fillColor: rl.Blank,
|
||||
reload: true,
|
||||
curTweens: make(map[string]*Tween),
|
||||
}
|
||||
r.tex = rl.LoadRenderTexture(width, height)
|
||||
rl.SetTextureFilter(r.tex.Texture, rl.FilterAnisotropic8x|rl.FilterBilinear)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Rect) Copy() *Rect {
|
||||
return &Rect{
|
||||
x: r.x,
|
||||
y: r.y,
|
||||
h: r.h,
|
||||
w: r.w,
|
||||
radius: r.radius,
|
||||
borderWidth: r.borderWidth,
|
||||
borderColor: r.borderColor,
|
||||
fillColor: r.fillColor,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) addTween(key string, old, new int32) {
|
||||
r.curTweens[key] = NewTween(old, new, 1000*time.Millisecond)
|
||||
}
|
||||
|
||||
func (r *Rect) SetPosition(x, y int32) {
|
||||
if !r.shown {
|
||||
r.x, r.y = x, y
|
||||
return
|
||||
}
|
||||
if r.x != x {
|
||||
r.addTween("x", r.x, x)
|
||||
}
|
||||
if r.y != y {
|
||||
r.addTween("y", r.y, y)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetSize(h, w int32) {
|
||||
if !r.shown {
|
||||
r.h, r.w = h, w
|
||||
return
|
||||
}
|
||||
if r.h != h {
|
||||
r.addTween("h", r.h, h)
|
||||
r.reload = true
|
||||
}
|
||||
if r.w != w {
|
||||
r.addTween("w", r.w, w)
|
||||
r.reload = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetBorderRadius(radius int32) {
|
||||
if !r.shown {
|
||||
r.radius = radius
|
||||
return
|
||||
}
|
||||
if r.radius != radius {
|
||||
r.addTween("radius", r.radius, radius)
|
||||
r.reload = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetBorderWidth(w int32) {
|
||||
if !r.shown {
|
||||
r.borderWidth = w
|
||||
return
|
||||
}
|
||||
if r.borderWidth != w {
|
||||
r.addTween("borderWidth", r.borderWidth, w)
|
||||
r.reload = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetBorderColor(c color.RGBA) {
|
||||
if r.borderColor != c {
|
||||
r.reload = true
|
||||
}
|
||||
r.borderColor = c
|
||||
}
|
||||
|
||||
func (r *Rect) SetFillColor(c color.RGBA) {
|
||||
if r.fillColor != c {
|
||||
r.reload = true
|
||||
}
|
||||
r.fillColor = c
|
||||
}
|
||||
|
||||
func (r *Rect) Draw() {
|
||||
r.shown = true
|
||||
if !r.reload && len(r.curTweens) == 0 {
|
||||
rl.DrawTextureEx(r.tex.Texture, rl.NewVector2(float32(r.x), float32(r.y)), 0, 1, rl.White)
|
||||
return
|
||||
}
|
||||
var curRect *Rect
|
||||
updateTex := false
|
||||
if len(r.curTweens) != 0 {
|
||||
curRect = r.Copy()
|
||||
tween, ok := r.curTweens["x"]
|
||||
if ok {
|
||||
curRect.x = tween.CurVal()
|
||||
if tween.Ended() {
|
||||
r.x = curRect.x
|
||||
delete(r.curTweens, "x")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["y"]
|
||||
if ok {
|
||||
curRect.y = tween.CurVal()
|
||||
if tween.Ended() {
|
||||
r.y = curRect.y
|
||||
delete(r.curTweens, "y")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["h"]
|
||||
if ok {
|
||||
curRect.h = tween.CurVal()
|
||||
if curRect.h != r.h {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.h = curRect.h
|
||||
delete(r.curTweens, "h")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["w"]
|
||||
if ok {
|
||||
curRect.w = tween.CurVal()
|
||||
if curRect.w != r.w {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.w = curRect.w
|
||||
delete(r.curTweens, "w")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["radius"]
|
||||
if ok {
|
||||
curRect.radius = tween.CurVal()
|
||||
if curRect.radius != r.radius {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.radius = curRect.radius
|
||||
delete(r.curTweens, "radius")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["borderWidth"]
|
||||
if ok {
|
||||
curRect.borderWidth = tween.CurVal()
|
||||
if curRect.borderWidth != r.borderWidth {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.borderWidth = curRect.borderWidth
|
||||
delete(r.curTweens, "borderWidth")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
curRect = r
|
||||
}
|
||||
if r.reload || updateTex {
|
||||
// rl.UnloadTexture(r.tex)
|
||||
// r.tex = rl.LoadTextureFromImage(curRect.buildImage())
|
||||
// rl.UpdateTexture(r.tex, rl.LoadImageColors(curRect.buildImage()))
|
||||
rl.BeginTextureMode(r.tex)
|
||||
curRect.drawTexture()
|
||||
rl.EndTextureMode()
|
||||
}
|
||||
rl.DrawTexturePro(r.tex.Texture, rl.NewRectangle(0, 0, float32(curRect.w), float32(curRect.h)), rl.NewRectangle(float32(curRect.x), float32(curRect.y), float32(curRect.w), float32(curRect.h)), rl.NewVector2(0, 0), 0, rl.White)
|
||||
// rl.DrawTextureEx(r.tex.Texture, rl.NewVector2(float32(curRect.x), float32(curRect.y)), 0, 1, rl.White)
|
||||
r.reload = false
|
||||
}
|
||||
|
||||
func (r Rect) drawTexture() {
|
||||
rl.ClearBackground(rl.Blank)
|
||||
// Filled areas
|
||||
if r.fillColor != rl.Blank {
|
||||
rl.DrawRectangle(r.radius, 0, (r.w - (2 * r.radius)), r.h, r.fillColor)
|
||||
if r.radius > 0 {
|
||||
rl.DrawRectangle((r.w - r.radius), r.radius, r.radius, (r.h - (2 * r.radius)), r.fillColor)
|
||||
rl.DrawRectangle(0, r.radius, r.radius, (r.h - (2 * r.radius)), r.fillColor)
|
||||
}
|
||||
}
|
||||
|
||||
if r.borderColor != rl.Blank {
|
||||
// Horizontal lines
|
||||
rl.DrawRectangle(r.radius, 0, (r.w - (2 * r.radius)), r.borderWidth, r.borderColor)
|
||||
rl.DrawRectangle(r.radius, (r.h)-(r.borderWidth), (r.w - (2 * r.radius)), r.borderWidth, r.borderColor)
|
||||
// Vertical lines
|
||||
rl.DrawRectangle(0, r.radius, r.borderWidth, (r.h - (2 * r.radius)), r.borderColor)
|
||||
rl.DrawRectangle((r.w)-(r.borderWidth), r.radius, r.borderWidth, (r.h - (2 * r.radius)), r.borderColor)
|
||||
}
|
||||
if r.radius > 0 {
|
||||
r.placeCorners()
|
||||
}
|
||||
}
|
||||
|
||||
func (r Rect) placeCorners() {
|
||||
//bl
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 180, 270, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), 180, 270, 20, r.fillColor)
|
||||
//tl
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 90, 180, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), 90, 180, 20, r.fillColor)
|
||||
//tr
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.w-r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 0, 90, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.w-r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), 0, 90, 20, r.fillColor)
|
||||
//br
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.w-r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 270, 360, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.w-r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), 270, 360, 20, r.fillColor)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type Window struct{}
|
||||
|
||||
func Test() {
|
||||
rl.SetConfigFlags(rl.FlagWindowResizable | rl.FlagWindowHighdpi | rl.FlagVsyncHint | rl.FlagMsaa4xHint)
|
||||
rl.InitWindow(800, 450, "raylib [core] example - basic window")
|
||||
defer rl.CloseWindow()
|
||||
rl.SetTargetFPS(60)
|
||||
|
||||
noto := rl.LoadFont("./noto-sans.ttf")
|
||||
txtImg := rl.ImageTextEx(noto, "Hello World!", 50, 0, rl.Black)
|
||||
txt := rl.LoadTextureFromImage(txtImg)
|
||||
|
||||
tmpRect := NewRect(10, 10, 250, 500)
|
||||
tmpRect.SetBorderRadius(25)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(5 * time.Second)
|
||||
// tmpRect.SetBorderRadius(0)
|
||||
// tmpRect.SetPosition(100, 100)
|
||||
tmpRect.SetSize(400, 700)
|
||||
time.Sleep(5 * time.Second)
|
||||
// tmpRect.SetBorderRadius(25)
|
||||
// tmpRect.SetPosition(10, 10)
|
||||
tmpRect.SetSize(250, 500)
|
||||
}
|
||||
}()
|
||||
// tmpRect.SetFillColor(rl.Green)
|
||||
for !rl.WindowShouldClose() {
|
||||
rl.BeginDrawing()
|
||||
rl.DrawFPS(0, 0)
|
||||
|
||||
rl.ClearBackground(rl.DarkGray)
|
||||
// rl.DrawText("Congrats! You created your first window!", 190, 100, 20, rl.LightGray)
|
||||
// // rl.DrawTextEx(noto, "Congrats! You created your first window!", rl.NewVector2(190, 200), 48, 0, rl.Black)
|
||||
tmpRect.Draw()
|
||||
rl.DrawTexture(txt, 50, 50, rl.Black)
|
||||
rl.EndDrawing()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Tween struct {
|
||||
startVal int32
|
||||
startTime time.Time
|
||||
dif int32
|
||||
dur time.Duration
|
||||
}
|
||||
|
||||
func NewTween(startVal, endVal int32, duration time.Duration) *Tween {
|
||||
return &Tween{
|
||||
startVal: startVal,
|
||||
dif: endVal - startVal,
|
||||
dur: duration,
|
||||
startTime: time.Now().Round(time.Millisecond),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tween) CurVal() int32 {
|
||||
since := time.Now().Round(time.Millisecond).Sub(t.startTime)
|
||||
if since <= 0 {
|
||||
return t.startVal
|
||||
}
|
||||
if since >= t.dur {
|
||||
return t.startVal + t.dif
|
||||
}
|
||||
m := float32(since.Milliseconds()) / float32(t.dur.Milliseconds())
|
||||
m = -1 * float32(math.Log10(-.9*float64(m)+1))
|
||||
return t.startVal + int32(math.Round(float64(float32(t.dif)*m)))
|
||||
}
|
||||
|
||||
func (t *Tween) Ended() bool {
|
||||
return time.Now().Round(time.Millisecond).Sub(t.startTime) >= t.dur
|
||||
}
|
||||
@@ -1,127 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/nelsam/gxui/drivers/gl"
|
||||
)
|
||||
|
||||
var (
|
||||
appMaster map[string][]prtap
|
||||
cats []string
|
||||
conf *os.File
|
||||
common string
|
||||
commEnbl bool
|
||||
)
|
||||
|
||||
type prtap struct {
|
||||
name string
|
||||
cat string
|
||||
ex string
|
||||
desc string
|
||||
}
|
||||
import "github.com/CalebQ42/LinuxPA/internal/ui"
|
||||
|
||||
func main() {
|
||||
commEnbl = true
|
||||
appMaster = make(map[string][]prtap)
|
||||
os.Mkdir("PortableApps", 0777)
|
||||
os.Mkdir("PortableApps/LinuxPACom", 0777)
|
||||
common = "PortableApps/LinuxPACom/common.sh"
|
||||
_, err := os.Open(common)
|
||||
if os.IsNotExist(err) {
|
||||
commEnbl = false
|
||||
}
|
||||
pa, err := os.Open("PortableApps")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
appstmp, _ := pa.Readdir(-1)
|
||||
var folds []string
|
||||
for _, v := range appstmp {
|
||||
if v.IsDir() && v.Name() != "LinuxPACom" {
|
||||
folds = append(folds, v.Name())
|
||||
}
|
||||
}
|
||||
sort.Strings(folds)
|
||||
for _, v := range folds {
|
||||
fi, _ := os.Open("PortableApps/" + v)
|
||||
pat := processApp(fi)
|
||||
if (pat != prtap{}) {
|
||||
if _, ok := appMaster[pat.cat]; !ok {
|
||||
cats = append(cats, pat.cat)
|
||||
}
|
||||
appMaster[pat.cat] = append(appMaster[pat.cat], pat)
|
||||
}
|
||||
}
|
||||
gl.StartDriver(uiMain)
|
||||
}
|
||||
|
||||
func processApp(fi *os.File) (out prtap) {
|
||||
fis, _ := fi.Readdir(-1)
|
||||
if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
|
||||
out.name = getName(fil)
|
||||
fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
|
||||
out.cat = getCat(fil)
|
||||
} else if fil, err := os.Open(fi.Name() + "/appinfo.ini"); err == nil {
|
||||
out.name = getName(fil)
|
||||
fil, _ = os.Open(fi.Name() + "/appinfo.ini")
|
||||
out.cat = getCat(fil)
|
||||
} else {
|
||||
out.cat = "other"
|
||||
}
|
||||
if out.name == "" {
|
||||
out.name = path.Base(fi.Name())
|
||||
}
|
||||
if out.cat == "" {
|
||||
out.cat = "other"
|
||||
}
|
||||
for _, v := range fis {
|
||||
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".sh") {
|
||||
//do os check here for possible cross platform support
|
||||
out.ex = fi.Name() + "/" + v.Name()
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, v := range fis {
|
||||
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".appimage") {
|
||||
//do os check here for possible cross platform support
|
||||
out.ex = fi.Name() + "/" + v.Name()
|
||||
return
|
||||
}
|
||||
}
|
||||
return prtap{}
|
||||
}
|
||||
|
||||
func getCat(fi *os.File) (out string) {
|
||||
rdr := bufio.NewReader(fi)
|
||||
var err error
|
||||
var ln []byte
|
||||
for err == nil {
|
||||
ln, _, err = rdr.ReadLine()
|
||||
str := string(ln)
|
||||
if strings.HasPrefix(str, "Category=") {
|
||||
out = strings.TrimPrefix(str, "Category=")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getName(fi *os.File) (out string) {
|
||||
rdr := bufio.NewReader(fi)
|
||||
var err error
|
||||
var ln []byte
|
||||
for err == nil {
|
||||
ln, _, err = rdr.ReadLine()
|
||||
str := string(ln)
|
||||
if strings.HasPrefix(str, "Name=") {
|
||||
out = strings.TrimPrefix(str, "Name=")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
ui.Test()
|
||||
}
|
||||
|
||||
Binary file not shown.
-103
@@ -1,103 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
_ "image/png"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/nelsam/gxui"
|
||||
"github.com/nelsam/gxui/math"
|
||||
)
|
||||
|
||||
type prtapAdap struct {
|
||||
gxui.AdapterBase
|
||||
apps []prtap
|
||||
}
|
||||
|
||||
func (p *prtapAdap) SetApps(apps []prtap) {
|
||||
p.apps = apps
|
||||
p.DataChanged(false)
|
||||
}
|
||||
|
||||
func (p *prtapAdap) Count() int {
|
||||
return len(p.apps)
|
||||
}
|
||||
|
||||
func (p *prtapAdap) Create(th gxui.Theme, index int) gxui.Control {
|
||||
box := th.CreateLinearLayout()
|
||||
box.SetPadding(math.CreateSpacing(2))
|
||||
box.SetDirection(gxui.LeftToRight)
|
||||
box.SetVerticalAlignment(gxui.AlignMiddle)
|
||||
dir := path.Dir(p.apps[index].ex)
|
||||
if fold, err := os.Open(dir + "/App/AppInfo"); err == nil {
|
||||
var pics []string
|
||||
fi, _ := fold.Readdirnames(-1)
|
||||
for _, v := range fi {
|
||||
if strings.HasPrefix(v, "appicon_") && strings.HasSuffix(v, ".png") {
|
||||
pics = append(pics, v)
|
||||
}
|
||||
}
|
||||
if len(pics) > 0 {
|
||||
ind := sort.SearchStrings(pics, "appicon_128.png")
|
||||
if ind == len(pics) {
|
||||
ind = len(pics) - 1
|
||||
}
|
||||
imgfi, _ := os.Open(dir + "/App/AppInfo/" + pics[ind])
|
||||
img, _, err := image.Decode(imgfi)
|
||||
if err == nil {
|
||||
rgba := image.NewRGBA(img.Bounds())
|
||||
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
||||
tex := dr.CreateTexture(rgba, 1)
|
||||
icon := th.CreateImage()
|
||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
||||
icon.SetTexture(tex)
|
||||
box.AddChild(icon)
|
||||
}
|
||||
}
|
||||
} else if fi, err := os.Open(dir + "/appicon.png"); err == nil {
|
||||
img, _, err := image.Decode(fi)
|
||||
if err == nil {
|
||||
rgba := image.NewRGBA(img.Bounds())
|
||||
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
||||
tex := dr.CreateTexture(rgba, 1)
|
||||
icon := th.CreateImage()
|
||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
||||
icon.SetTexture(tex)
|
||||
box.AddChild(icon)
|
||||
}
|
||||
} else {
|
||||
//Creating empty Image so that names line up
|
||||
icon := th.CreateImage()
|
||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
||||
box.AddChild(icon)
|
||||
}
|
||||
lbl := th.CreateLabel()
|
||||
lbl.SetText(p.apps[index].name)
|
||||
box.AddChild(lbl)
|
||||
return box
|
||||
}
|
||||
|
||||
func (p *prtapAdap) ItemAt(index int) gxui.AdapterItem {
|
||||
return p.apps[index]
|
||||
}
|
||||
|
||||
func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int {
|
||||
it, ok := item.(prtap)
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
for i, v := range p.apps {
|
||||
if v == it {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (p *prtapAdap) Size(gxui.Theme) math.Size {
|
||||
return math.Size{W: math.MaxSize.W, H: 36}
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/nelsam/gxui"
|
||||
"github.com/nelsam/gxui/math"
|
||||
)
|
||||
|
||||
//StrList TODO
|
||||
type StrList struct {
|
||||
gxui.AdapterBase
|
||||
strs []string
|
||||
}
|
||||
|
||||
//AddString TODO
|
||||
func (s *StrList) AddString(add string) {
|
||||
s.strs = append(s.strs, add)
|
||||
s.DataChanged(false)
|
||||
}
|
||||
|
||||
//Remove TODO
|
||||
func (s *StrList) Remove(index int) {
|
||||
s.strs = append(s.strs[:index], s.strs[index+1:]...)
|
||||
s.DataChanged(false)
|
||||
}
|
||||
|
||||
//SetStrings TODO
|
||||
func (s *StrList) SetStrings(strs []string) {
|
||||
s.strs = strs
|
||||
s.DataChanged(false)
|
||||
}
|
||||
|
||||
//Count TODO
|
||||
func (s *StrList) Count() int {
|
||||
return len(s.strs)
|
||||
}
|
||||
|
||||
//ItemAt TODO
|
||||
func (s *StrList) ItemAt(index int) gxui.AdapterItem {
|
||||
return s.strs[index]
|
||||
}
|
||||
|
||||
//ItemIndex TODO
|
||||
func (s *StrList) ItemIndex(item gxui.AdapterItem) int {
|
||||
for i, v := range s.strs {
|
||||
if v == item {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
//Create TODO
|
||||
func (s *StrList) Create(th gxui.Theme, index int) gxui.Control {
|
||||
box := th.CreateLinearLayout()
|
||||
box.SetDirection(gxui.LeftToRight)
|
||||
lbl := th.CreateLabel()
|
||||
lbl.SetText(s.strs[index])
|
||||
box.AddChild(lbl)
|
||||
return box
|
||||
}
|
||||
|
||||
//Size TODO
|
||||
func (s *StrList) Size(gxui.Theme) math.Size {
|
||||
return math.Size{W: math.MaxSize.W, H: 20}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
||||
"github.com/nelsam/gxui"
|
||||
"github.com/nelsam/gxui/themes/dark"
|
||||
)
|
||||
|
||||
var (
|
||||
dr gxui.Driver
|
||||
)
|
||||
|
||||
func uiMain(dri gxui.Driver) {
|
||||
dr = dri
|
||||
catAdap := &StrList{}
|
||||
catAdap.SetStrings(cats)
|
||||
appAdap := &prtapAdap{}
|
||||
th := dark.CreateTheme(dr)
|
||||
win := th.CreateWindow(500, 500, "LinuxPA")
|
||||
top := th.CreateLinearLayout()
|
||||
top.SetDirection(gxui.BottomToTop)
|
||||
top.SetHorizontalAlignment(gxui.AlignRight)
|
||||
spl := th.CreateSplitterLayout()
|
||||
spl.SetOrientation(gxui.Horizontal)
|
||||
catlist := th.CreateList()
|
||||
catlist.SetAdapter(catAdap)
|
||||
catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
|
||||
str := it.(string)
|
||||
appAdap.SetApps(appMaster[str])
|
||||
})
|
||||
applist := th.CreateList()
|
||||
applist.SetAdapter(appAdap)
|
||||
spl.AddChild(catlist)
|
||||
spl.AddChild(applist)
|
||||
but := th.CreateLinearLayout()
|
||||
but.SetDirection(gxui.RightToLeft)
|
||||
launch := th.CreateButton()
|
||||
launch.SetText("Launch!")
|
||||
launch.OnClick(func(gxui.MouseEvent) {
|
||||
if appAdap.ItemIndex(applist.Selected()) != -1 {
|
||||
app := applist.Selected().(prtap)
|
||||
dir, fi := path.Split(app.ex)
|
||||
var cmd *exec.Cmd
|
||||
if commEnbl {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
|
||||
}
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Start()
|
||||
}
|
||||
})
|
||||
but.AddChild(launch)
|
||||
top.AddChild(but)
|
||||
top.AddChild(spl)
|
||||
win.AddChild(top)
|
||||
win.OnClose(func() {
|
||||
dr.Terminate()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user