From 7cf45c9ac8c3608400400f9216b9588dc2175439 Mon Sep 17 00:00:00 2001 From: Belac Darkstorm Date: Thu, 22 Sep 2016 00:11:32 -0500 Subject: [PATCH] Allow for multiple executables. Double click to launch instead of the launch button --- README.md | 6 +- app.go | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 187 ++++--------------------------------- prtapAdap.go | 130 -------------------------- setup.go | 168 +++++++++++++++++++++++++++++++++ strList.go | 0 ui.go | 103 +++++++------------- 7 files changed, 480 insertions(+), 373 deletions(-) create mode 100644 app.go delete mode 100644 prtapAdap.go create mode 100644 setup.go mode change 100755 => 100644 strList.go diff --git a/README.md b/README.md index 1f01f9f..eff18e0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # LinuxPA LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux. -# App Detection -LinuxPA looks in all folders in the PortableApps folder for, first, a script file (starts with the shebang (`#!`)) and, secondly, a native linux executable (starts with ELF). It will only add the first one it finds. +# How to use +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, but if one isn't found it launches the first executable in general. # PortableApps.com Compatibility 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. @@ -15,7 +15,7 @@ Because apps aren't natively formated in the PortableApps.com format, if LinuxPA # AppImage Support [AppImage Website](http://appimage.org) -Right now AppImages are simply supported via the native linux executable support, but later I'm hoping to add downloading and automatic updating support. +Right now AppImages are simply supported via the native linux executable support, but later I'm hoping to add downloading and automatic updating support later on. # USB mount Unfortunately Linux, by default, doesn't support running executables off of flash drives, requiring you to mount your drive with special mount arguments, I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000` diff --git a/app.go b/app.go new file mode 100644 index 0000000..18e4cad --- /dev/null +++ b/app.go @@ -0,0 +1,259 @@ +package main + +import ( + "os" + "os/exec" + "sort" + + "github.com/nelsam/gxui" + "github.com/nelsam/gxui/math" +) + +type app struct { + name string + cat string + appimg []string + lin []string + ex []string + icon gxui.Texture + dir string + ini *os.File +} + +type appExNode struct { + ap app + exInd int +} + +func (a *appExNode) launch() { + if wine { + var cmd *exec.Cmd + if ind := sort.SearchStrings(a.ap.lin, a.ap.ex[a.exInd]); ind == len(a.ap.lin) { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[a.exInd]+"\"") + } else { + if comEnbld { + cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"") + } else { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"") + } + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Start() + } + var cmd *exec.Cmd + if comEnbld { + cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"") + } else { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"") + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Start() +} + +func (a *appExNode) Count() int { + return 0 +} + +func (a *appExNode) NodeAt(int) gxui.TreeNode { + return nil +} + +func (a *appExNode) ItemIndex(gxui.AdapterItem) int { + return -1 +} + +func (a *appExNode) Item() gxui.AdapterItem { + if wine { + return a.ap.ex[a.exInd] + } + return a.ap.lin[a.exInd] +} + +func (a *appExNode) Create(the gxui.Theme) gxui.Control { + box := the.CreateLinearLayout() + box.SetDirection(gxui.LeftToRight) + box.SetVerticalAlignment(gxui.AlignMiddle) + img := the.CreateImage() + img.SetTexture(a.ap.icon) + img.SetExplicitSize(math.Size{H: 32, W: 32}) + lbl := the.CreateLabel() + lbl.SetText(a.ap.ex[a.exInd]) + box.AddChild(img) + box.AddChild(lbl) + box.OnDoubleClick(func(gxui.MouseEvent) { + a.launch() + }) + return box +} + +type appNode struct { + ap app +} + +func (a *appNode) launch() { + + if len(a.ap.ex) == 1 { + if wine { + var cmd *exec.Cmd + if ind := sort.SearchStrings(a.ap.lin, a.ap.ex[0]); ind == len(a.ap.lin) { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"") + } else { + if comEnbld { + cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"") + } else { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"") + } + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Start() + } else { + var cmd *exec.Cmd + if comEnbld { + cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"") + } else { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"") + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Start() + } + } else { + if wine { + var cmd *exec.Cmd + if len(a.ap.lin) == 0 { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"") + } else { + if comEnbld { + cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"") + } else { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"") + } + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Start() + } else { + if len(a.ap.lin) != 0 { + var cmd *exec.Cmd + if comEnbld { + cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"") + } else { + cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"") + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Start() + } + } + } +} + +func (a *appNode) Count() int { + if wine { + if len(a.ap.ex) > 1 { + return len(a.ap.ex) + } + return 0 + } + if len(a.ap.lin) > 1 { + return len(a.ap.lin) + } + return 0 +} + +func (a *appNode) NodeAt(i int) gxui.TreeNode { + return &appExNode{ap: a.ap, exInd: i} +} + +func (a *appNode) ItemIndex(item gxui.AdapterItem) int { + if wine { + for i, v := range a.ap.ex { + if v == item { + return i + } + } + } else { + for i, v := range a.ap.lin { + if v == item { + return i + } + } + } + return -1 +} + +func (a *appNode) Item() gxui.AdapterItem { + return a.ap.name +} + +func (a *appNode) Create(the gxui.Theme) gxui.Control { + box := the.CreateLinearLayout() + box.SetDirection(gxui.LeftToRight) + box.SetPadding(math.CreateSpacing(2)) + box.SetVerticalAlignment(gxui.AlignMiddle) + img := the.CreateImage() + if a.ap.icon != nil { + img.SetTexture(a.ap.icon) + } + img.SetExplicitSize(math.Size{H: 32, W: 32}) + lbl := the.CreateLabel() + lbl.SetText(a.ap.name) + box.AddChild(img) + box.AddChild(lbl) + box.OnDoubleClick(func(gxui.MouseEvent) { + a.launch() + }) + return box +} + +type catAdap struct { + gxui.AdapterBase + cat string +} + +func (a *catAdap) setCat(cat string) { + a.cat = cat + a.DataChanged(false) +} + +func (a *catAdap) refresh() { + a.DataChanged(false) +} + +func (a *catAdap) Count() int { + if wine { + return len(master[a.cat]) + } + return len(linmaster[a.cat]) +} + +func (a *catAdap) NodeAt(i int) gxui.TreeNode { + if wine { + return &appNode{ap: master[a.cat][i]} + } + return &appNode{ap: linmaster[a.cat][i]} +} + +func (a *catAdap) Size(gxui.Theme) math.Size { + return math.Size{H: 34, W: math.MaxSize.W} +} + +func (a *catAdap) ItemIndex(item gxui.AdapterItem) int { + if wine { + for i, v := range master[a.cat] { + if v.name == item { + return i + } + } + } else { + for i, v := range linmaster[a.cat] { + if v.name == item { + return i + } + } + } + return -1 +} diff --git a/main.go b/main.go index 126da4b..d5ad9e4 100644 --- a/main.go +++ b/main.go @@ -1,184 +1,31 @@ package main import ( - "bufio" - "os" - "path" - "reflect" - "sort" - "strings" - + "github.com/nelsam/gxui" "github.com/nelsam/gxui/drivers/gl" + "github.com/nelsam/gxui/themes/dark" ) var ( - appMaster map[string][]prtap + dr gxui.Driver + th gxui.Theme + master map[string][]app + linmaster map[string][]app cats []string - wineOnly []string - linOnly []string - conf *os.File - common string - commEnbl bool + lin []string + wine bool + comEnbld bool ) -type prtap struct { - name string - cat string - ex string - desc string - wine bool -} - 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" && v.Name() != "PortableApps.com" { - 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 { - if pat.wine { - wineOnly = append(wineOnly, pat.cat) - cats = append(cats, pat.cat) - } else { - linOnly = append(linOnly, pat.cat) - cats = append(cats, pat.cat) - } - } else { - if !pat.wine { - for i, v := range wineOnly { - if pat.cat == v { - wineOnly = append(wineOnly[:i], wineOnly[i+1:]...) - linOnly = append(linOnly, pat.cat) - break - } - } - } - } - appMaster[pat.cat] = append(appMaster[pat.cat], pat) - } - } - sort.Strings(linOnly) - sort.Strings(wineOnly) - sort.Strings(cats) - gl.StartDriver(uiMain) + master = make(map[string][]app) + linmaster = make(map[string][]app) + gl.StartDriver(appMain) } -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" - } - //executable detection - wd, _ := os.Getwd() - var rdr *bufio.Reader - for _, v := range fis { - fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name()) - if err == nil { - stat, _ := fil.Stat() - if !stat.IsDir() { - rdr = bufio.NewReader(fil) - shebang := []byte{'#', '!'} - two := make([]byte, 2) - rdr.Read(two) - if reflect.DeepEqual(shebang, two) { - out.ex = wd + "/" + fi.Name() + "/" + v.Name() - rdr.Reset(fil) - return - } - } - } - } - for _, v := range fis { - fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name()) - if err == nil { - stat, _ := fil.Stat() - if !stat.IsDir() { - rdr = bufio.NewReader(fil) - thr := make([]byte, 4) - rdr.Read(thr) - if strings.Contains(string(thr), "ELF") { - out.ex = wd + "/" + fi.Name() + "/" + v.Name() - rdr.Reset(fil) - return - } - } - } - } - for _, v := range fis { - fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name()) - if err == nil { - stat, _ := fil.Stat() - if !stat.IsDir() && strings.HasSuffix(stat.Name(), "exe") { - out.wine = true - out.ex = wd + "/" + fi.Name() + "/" + v.Name() - out.name += " (Wine)" - 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 +func appMain(dri gxui.Driver) { + dr = dri + th = dark.CreateTheme(dr) + setup() + ui() } diff --git a/prtapAdap.go b/prtapAdap.go deleted file mode 100644 index 400a9a9..0000000 --- a/prtapAdap.go +++ /dev/null @@ -1,130 +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 - wine bool - master []prtap - cur []prtap -} - -func (p *prtapAdap) SetApps(apps []prtap) { - p.master = apps - if p.wine { - p.cur = p.master - } else { - p.cur = make([]prtap, 0) - for _, v := range p.master { - if !v.wine { - p.cur = append(p.cur, v) - } - } - } - p.DataChanged(false) -} - -func (p *prtapAdap) Count() int { - return len(p.cur) -} - -func (p *prtapAdap) Wine(show bool) { - p.wine = show - if show { - p.cur = p.master - } else { - p.cur = make([]prtap, 0) - for _, v := range p.master { - if !v.wine { - p.cur = append(p.cur, v) - } - } - } - p.DataChanged(false) -} - -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.cur[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.cur[index].name) - box.AddChild(lbl) - return box -} - -func (p *prtapAdap) ItemAt(index int) gxui.AdapterItem { - return p.cur[index] -} - -func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int { - it, ok := item.(prtap) - if !ok { - return -1 - } - for i, v := range p.cur { - if v == it { - return i - } - } - return -1 -} - -func (p *prtapAdap) Size(gxui.Theme) math.Size { - return math.Size{W: math.MaxSize.W, H: 36} -} diff --git a/setup.go b/setup.go new file mode 100644 index 0000000..6d6f73f --- /dev/null +++ b/setup.go @@ -0,0 +1,168 @@ +package main + +import ( + "bufio" + "image" + "image/draw" + _ "image/png" + "os" + "reflect" + "sort" + "strings" + + "github.com/nelsam/gxui" +) + +func setup() { + PortableAppsFold, err := os.Open("PortableApps") + if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() { + panic("PortableApps folder not found!!") + } + PAFolds, _ := PortableAppsFold.Readdirnames(-1) + sort.Strings(PAFolds) + for _, v := range PAFolds { + fold, _ := os.Open("PortableApps/" + v) + if stat, _ := fold.Stat(); stat.IsDir() { + ap := processApp("PortableApps/" + v) + if !reflect.DeepEqual(ap, app{}) { + if _, ok := master[ap.cat]; !ok { + cats = append(cats, ap.cat) + sort.Strings(cats) + if len(ap.lin) != 0 { + lin = append(lin, ap.cat) + sort.Strings(lin) + } + } else { + if len(ap.lin) != 0 { + ind := sort.SearchStrings(lin, ap.cat) + if ind == len(lin) { + lin = append(lin, ap.cat) + sort.Strings(lin) + } + } + } + if len(ap.lin) != 0 { + linmaster[ap.cat] = append(linmaster[ap.cat], ap) + } + master[ap.cat] = append(master[ap.cat], ap) + } + } + } +} + +func processApp(fold string) (out app) { + wd, _ := os.Getwd() + out.dir = wd + "/" + fold + out.ini = findInfo(fold) + if out.ini != nil { + out.name = getName(out.ini) + out.ini = findInfo(fold) + out.cat = getCat(out.ini) + out.ini = findInfo(fold) + } + if out.name == "" { + out.name = strings.TrimPrefix(fold, "PortableApps/") + } + if out.cat == "" { + out.cat = "Other" + } + out.icon = getIcon(fold) + folder, _ := os.Open(fold) + fis, _ := folder.Readdirnames(-1) + for _, v := range fis { + tmp, _ := os.Open(fold + "/" + v) + if stat, _ := tmp.Stat(); stat.IsDir() { + continue + } + if strings.HasSuffix(strings.ToLower(v), ".appimage") { + out.appimg = append(out.appimg, v) + out.ex = append(out.ex, v) + out.lin = append(out.lin, v) + } else if strings.HasSuffix(strings.ToLower(v), ".exe") { + out.ex = append(out.ex, v) + } else { + btys := make([]byte, 4) + rdr := bufio.NewReader(tmp) + rdr.Read(btys) + if strings.HasPrefix(strings.ToLower(string(btys)), "ELF") || strings.HasPrefix(strings.ToLower(string(btys)), "#!") { + out.ex = append(out.ex, v) + out.lin = append(out.lin, v) + } + } + } + if len(out.ex) == 0 { + return app{} + } + if len(out.lin) == 0 { + out.name += " (Wine)" + } + return +} + +func getCat(ini *os.File) string { + rdr := bufio.NewReader(ini) + var ret string + for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() { + if strings.HasPrefix(string(line), "Category=") { + ret = strings.TrimPrefix(string(line), "Category=") + break + } + } + rdr.Reset(ini) + return ret +} + +func getName(ini *os.File) string { + rdr := bufio.NewReader(ini) + var ret string + for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() { + if strings.HasPrefix(string(line), "Name=") { + ret = strings.TrimPrefix(string(line), "Name=") + break + } + } + rdr.Reset(ini) + return ret +} + +func getIcon(fold string) gxui.Texture { + var pic *os.File + if folder, err := os.Open(fold + "/App/AppInfo"); err == nil { + fis, _ := folder.Readdir(-1) + var pics []string + for _, v := range fis { + if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".png") && strings.HasPrefix(strings.ToLower(v.Name()), "appicon_") { + pics = append(pics, v.Name()) + } + } + sort.Strings(pics) + if len(pics) > 1 { + ind := sort.SearchStrings(pics, "appicon_32.png") + if ind == len(pics) { + ind-- + } + pic, _ = os.Open(fold + "/App/AppInfo/" + pics[ind]) + } + } else if fi, err := os.Open(fold + "/appicon.png"); err == nil { + pic = fi + } else { + return nil + } + img, _, err := image.Decode(pic) + if err != nil { + return nil + } + rgba := image.NewRGBA(img.Bounds()) + draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src) + ret := dr.CreateTexture(rgba, 1) + return ret +} + +func findInfo(fold string) *os.File { + if fi, err := os.Open(fold + "/App/AppInfo/appinfo.ini"); err == nil { + return fi + } else if fi, err := os.Open(fold + "/appinfo.ini"); err == nil { + return fi + } + return nil +} diff --git a/strList.go b/strList.go old mode 100755 new mode 100644 diff --git a/ui.go b/ui.go index b0f8768..59bdaa6 100644 --- a/ui.go +++ b/ui.go @@ -1,90 +1,53 @@ package main import ( - "fmt" - "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(linOnly) - appAdap := &prtapAdap{} - appAdap.Wine(false) - th := dark.CreateTheme(dr) - win := th.CreateWindow(500, 500, "LinuxPA") +func ui() { + catListAdap := &StrList{} + appListAdap := &catAdap{} + catListAdap.SetStrings(lin) + win := th.CreateWindow(600, 500, "LinuxPA") top := th.CreateLinearLayout() top.SetDirection(gxui.BottomToTop) - top.SetHorizontalAlignment(gxui.AlignRight) + splBox := th.CreateLinearLayout() 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 app.wine { - cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; wine \""+fi+"\"") - } else { - 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.Stderr = os.Stderr - cmd.Start() - } + catList := th.CreateList() + catList.SetAdapter(catListAdap) + catList.OnSelectionChanged(func(it gxui.AdapterItem) { + appListAdap.setCat(it.(string)) }) + appList := th.CreateTree() + appList.SetAdapter(appListAdap) + spl.AddChild(catList) + spl.AddChild(appList) + splBox.AddChild(spl) + butBox := th.CreateLinearLayout() + butBox.SetDirection(gxui.LeftToRight) if _, err := exec.LookPath("wine"); err == nil { - fmt.Println("Wine found!") - wine := th.CreateButton() - wine.SetType(gxui.ToggleButton) - wine.OnClick(func(gxui.MouseEvent) { - if wine.IsChecked() { - catAdap.SetStrings(cats) - appAdap.Wine(true) + wineBut := th.CreateButton() + wineBut.SetType(gxui.ToggleButton) + wineBut.SetChecked(wine) + wineBut.SetText("Show Windows Apps") + wineBut.OnClick(func(gxui.MouseEvent) { + wine = wineBut.IsChecked() + appListAdap.refresh() + if wineBut.IsChecked() { + catListAdap.SetStrings(cats) + wineBut.SetText("Hide Windows Apps") } else { - catAdap.SetStrings(linOnly) - appAdap.Wine(false) + catListAdap.SetStrings(lin) + wineBut.SetText("Show Windows Apps") } }) - wine.SetText("Show Windows Apps") - wine.SetChecked(appAdap.wine) - but.AddChild(wine) - } else { - fmt.Println("Wine not found!") + butBox.AddChild(wineBut) } - but.AddChild(launch) - top.AddChild(but) - top.AddChild(spl) + top.AddChild(butBox) + top.AddChild(splBox) win.AddChild(top) - win.OnClose(func() { - dr.Terminate() - }) + win.OnClose(dr.Terminate) }