From 38a7c1026842433a5d3799bb1d9c3b08c90ea9f8 Mon Sep 17 00:00:00 2001 From: Belac Darkstorm Date: Thu, 1 Sep 2016 07:39:41 -0500 Subject: [PATCH] Added icon support! Added launch button! Updated README! --- README.md | 9 +++++--- main.go | 60 +++++++++++++++++++++++----------------------------- prtapAdap.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++----- strList.go | 31 --------------------------- ui.go | 34 +++++++++++++++++++---------- 5 files changed, 110 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index adf8791..c2c1beb 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The goal is to create a fully functional PortableApps.com type launcher that can 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, not to mention DRM-free games), 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. +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. # 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). @@ -14,9 +14,12 @@ Because I like Go :) Also the way it includes all it needs into one friendly exe # 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). +# 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). + # TODO -Add in support to show an app's icon. Add in a common.sh that is executed with each script. (Allows for setting environment variables such as HOME) MAKE IT BETTER Add an open button (I know, I just wanted to get the initial working before making it user friendly) -(Maybe)Add an installer. +Check if all apps are closed when it closes and ask if you want to force stop the apps. +(Maybe)Create an installer. diff --git a/main.go b/main.go index 3d4fd9e..4bf01ce 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,8 @@ package main import ( "bufio" - "fmt" "os" + "path" "sort" "strings" @@ -50,46 +50,42 @@ func main() { } func processApp(fi *os.File) (out prtap) { - var hasEx bool - out.cat = "other" fis, _ := fi.Readdir(-1) - for _, v := range fis { - if v.IsDir() && v.Name() == "App" { - fild, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini") - fmt.Println(fi.Name() + "/App/AppInfo/appinfo.ini") - if err == nil { - fmt.Println("working!") - out.name = getName(*fild) - fild, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini") - out.cat = getCat(*fild) - fmt.Println("Name:", out.name) - } - } else if !v.IsDir() { - //do os check here - if strings.HasSuffix(v.Name(), ".sh") { - hasEx = true - out.ex = fi.Name() + "/" + v.Name() - if out.name == "" { - out.name = strings.TrimSuffix(v.Name(), ".sh") - } - } - } + 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 hasEx { - return + if out.name == "" { + out.name = path.Base(fi.Name()) + } + if out.cat == "" { + out.cat = "other" + } + for _, v := range fis { + if !v.IsDir() && strings.HasSuffix(v.Name(), ".sh") { + //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) +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=") { - fmt.Println(str) out = strings.TrimPrefix(str, "Category=") return } @@ -97,15 +93,13 @@ func getCat(fi os.File) (out string) { return } -func getName(fi os.File) (out string) { - rdr := bufio.NewReader(&fi) +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) - fmt.Println(str) if strings.HasPrefix(str, "Name=") { out = strings.TrimPrefix(str, "Name=") return diff --git a/prtapAdap.go b/prtapAdap.go index 39d92eb..17bd6ef 100644 --- a/prtapAdap.go +++ b/prtapAdap.go @@ -1,6 +1,14 @@ package main import ( + "image" + "image/draw" + _ "image/png" + "os" + "path" + "sort" + "strings" + "github.com/nelsam/gxui" "github.com/nelsam/gxui/math" ) @@ -21,13 +29,54 @@ func (p *prtapAdap) Count() int { func (p *prtapAdap) Create(th gxui.Theme, index int) gxui.Control { box := th.CreateLinearLayout() + box.SetPadding(math.CreateSpacing(2)) box.SetDirection(gxui.LeftToRight) - //add image support - // pic := th.CreateImage() - // dr.CreateTexture() + 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(pic) box.AddChild(lbl) return box } @@ -50,5 +99,5 @@ func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int { } func (p *prtapAdap) Size(gxui.Theme) math.Size { - return math.Size{W: math.MaxSize.W, H: 20} + return math.Size{W: math.MaxSize.W, H: 36} } diff --git a/strList.go b/strList.go index 40490cc..35a1e19 100755 --- a/strList.go +++ b/strList.go @@ -1,9 +1,6 @@ package main import ( - "encoding/gob" - "os" - "github.com/nelsam/gxui" "github.com/nelsam/gxui/math" ) @@ -32,34 +29,6 @@ func (s *StrList) SetStrings(strs []string) { s.DataChanged(false) } -func (s *StrList) Save(filename string) { - os.Remove(filename) - fi, err := os.Create(filename) - if err != nil { - panic(err) - } - e := gob.NewEncoder(fi) - err = e.Encode(s.strs) - if err != nil { - panic(err) - } - fi.Close() -} - -func (s *StrList) Load(filename string) { - fi, err := os.Open(filename) - if err != nil { - return - } - d := gob.NewDecoder(fi) - err = d.Decode(&s.strs) - if err != nil { - panic(err) - } - fi.Close() - s.DataChanged(false) -} - //Count TODO func (s *StrList) Count() int { return len(s.strs) diff --git a/ui.go b/ui.go index 49c3ddb..42126d6 100644 --- a/ui.go +++ b/ui.go @@ -20,8 +20,11 @@ func uiMain(dri gxui.Driver) { appAdap := &prtapAdap{} th := dark.CreateTheme(dr) win := th.CreateWindow(500, 500, "LinuxPA") - top := th.CreateSplitterLayout() - top.SetOrientation(gxui.Horizontal) + 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) { @@ -30,16 +33,25 @@ func uiMain(dri gxui.Driver) { }) applist := th.CreateList() applist.SetAdapter(appAdap) - applist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) { - app := it.(prtap) - dir, fi := path.Split(app.ex) - cmd := exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"") - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Start() + 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) + cmd := exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"") + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Start() + } }) - top.AddChild(catlist) - top.AddChild(applist) + but.AddChild(launch) + top.AddChild(but) + top.AddChild(spl) win.AddChild(top) win.OnClose(dr.Terminate) }