pdb / demo / demo.go

package main

import (
	"log"
	"os"
	"path"
	"strconv"
//	"fmt"
	"sort"
	"strings"
	"gtk"
//	"gdkpixbuf"

)

var (
	title string = "IRAM - Plateau de Bure model"
	programName string = "Pdb-model"
	authors []string = []string{
		"Mathieu Lonjaret <lonjaret@iram.fr>",
		"Roberto Garcia <garcia@iram.fr>"}
	comments string = "Program interacting with the plateau de bure model, showing images at various resolutions depending on the model's input. The model was designed by Mathieu Lonjaret, Karin Zacher, Roberto Garcia, Bastien Lefranc and the iram mechanical construction team."
	license string = "This program is available under the terms and conditions of the BSD style license."
	imagesPath string = "../images"
	suffixes = []string{".jpg", ".jpeg", ".png"}
	maxNbImages int = 8
	signaltoconf = map[int]int{
		41: 1, 
		25: 2,
		37: 2, 
		21: 4,
		42: 5,
		26: 6,
		38: 7,
		22: 8,
	}
)

// Mapping of the signal to the antennae configuration.
//We define the positions as the following:
//1---------2----------3----4
//				|
//				5
//				|
//				6
//and the positions are encoded as the positions of bits in a byte.
//For example, if the 3 antennae are in position 1, 3 and 5, the bits
//are 00010101, and hence the signal sent is 21.
//The configurations are ordered in reverse compactness order, i.e
//configuration 1 is the most spread out (best resolution, while
//configuration 6 is the most compact.  Thus, the mapping is (cf
//signaltoconf map):
//41: 1, (00101001)
//25: 2, (00011001)
//37: 3, (00100101)
//21: 4, (00010101)
//42: 5, (00101010)
//26: 6, (00011010)
//38: 7, (00100110)
//22: 8, (00010110)

type lineReader struct {
	*os.File
}

//TODO: prevent overflow over 3 chars
func (lr *lineReader) readLine() (line string) {
	var b []uint8 = make([]uint8, 1)
	bline := make([]byte, 3)
	i:= 0
	for ;; {
		_, err := lr.File.Read(b)
		if err != nil {
			log.Exit(err)
		}
		bline[i] = b[0] // + 48
		if b[0] == '\n' {
			line = string(bline[0:i])
			break
		}
		i++
	}
	return line
}

//TODO: lineReader is very lame, there must be a much simpler way with a Scan func
func readSignal(c chan int) {
	lr := &lineReader{os.Stdin}
	var lastSignal int = 0
	for ;; {
		signal, err := strconv.Atoi(lr.readLine())
		if err != nil {
			log.Exit(err)
		}
		if signal != lastSignal {
			c <- signal
			lastSignal = signal
		}
	}
}

type images struct {
	dir string
	dirs []string
	paths []string
	bufs []*gtk.GtkImage
	visible *gtk.GtkImage
}

func (imgs *images) setImagesDirs(dirPath string) os.Error {
	currentDir, err := os.Open(dirPath, os.O_RDONLY, 0644)
	if err != nil {
		return err
	}
	names, err := currentDir.Readdirnames(-1)
	if err != nil {
		return err
	}
	currentDir.Close()

//TODO: don't hardcode that, or make it able to grow
	dirs := make([]string, 15)
	counter := 0
	sort.SortStrings(names)
	for _, v := range names {
		fullpath := path.Join(dirPath, v)
		fi, err := os.Lstat(fullpath)
		if err != nil {
			return err
		}
		if fi.IsDirectory() {
			dirs[counter] = fullpath
				counter++
		}
	}
	dirs = dirs[0:counter]
	imgs.dirs = dirs
	return nil
}

func (imgs *images) setImagesPaths(dirPath string) os.Error {
	imgs.dir = dirPath
	currentDir, err := os.Open(dirPath, os.O_RDONLY, 0644)
	if err != nil {
		return err
	}
	names, err := currentDir.Readdirnames(-1)
	if err != nil {
		return err
	}
	currentDir.Close()

	images := make([]string, maxNbImages)
	counter := 0
	sort.SortStrings(names)
	for _, v := range names {
		for _, suffix := range suffixes {
			if strings.Index(v,	suffix) != -1 {
				images[counter] = path.Join(dirPath, v)
				counter++
				break
			}
		}
	}
	images = images[0:counter]
	imgs.paths = images
	return nil
}

func (imgs *images) loadImages() {
	images := make([]*gtk.GtkImage, len(imgs.paths))
	for i, v := range imgs.paths {
		images[i] = gtk.ImageFromFile(v)
	}
	imgs.bufs = images
}

func (imgs *images) chooseImagesDir(dirPath string) os.Error {
	err := imgs.setImagesPaths(dirPath)
	if err != nil {
		return err
	}
	imgs.loadImages()
	return nil
}

func gtkStuff(c chan int) {
	//init gtk stuff
	gtk.Init(nil)
	window := gtk.Window(gtk.GTK_WINDOW_TOPLEVEL)
	window.SetTitle(title)
	window.Connect("destroy", func(w *gtk.GtkWidget, user_data string) {
		println("got destroy!", user_data)
		gtk.MainQuit()
	},
		"foo")

	// preload images
	dir, _ := path.Split(os.Args[0])
	var imgs images
	err := imgs.setImagesDirs(path.Join(dir, imagesPath))
	if err != nil {
		log.Exit(err)
	}
//TODO: check if imgs.dirs[0] exists
	err = imgs.setImagesPaths(imgs.dirs[0])
	if err != nil {
		log.Exit(err)
	}
	imgs.loadImages()

	//--------------------------------------------------------
	// GtkVBox
	//--------------------------------------------------------
	vbox := gtk.VBox(false, 1)

	//--------------------------------------------------------
	// GtkMenuBar
	//--------------------------------------------------------
	menubar := gtk.MenuBar()
	vbox.PackStart(menubar, false, false, 0)

	//--------------------------------------------------------
	// GtkMenuItem
	//--------------------------------------------------------
	filemenu := gtk.MenuItemWithMnemonic("_File")
	menubar.Append(filemenu)
	filesubmenu := gtk.Menu()
	filemenu.SetSubmenu(filesubmenu)
	exitmenuitem := gtk.MenuItemWithMnemonic("E_xit")
	exitmenuitem.Connect("activate",func() { os.Exit(0) }, nil)
	filesubmenu.Append(exitmenuitem)

	filemenu = gtk.MenuItemWithMnemonic("_Help")
	menubar.Append(filemenu)
	filesubmenu = gtk.Menu()
	filemenu.SetSubmenu(filesubmenu)
	exitmenuitem = gtk.MenuItemWithMnemonic("_About")
	exitmenuitem.Connect("activate", func() {
		dialog := gtk.AboutDialog()
		dialog.SetName(title)
		dialog.SetProgramName(programName)
		dialog.SetAuthors(authors)
		dialog.SetComments(comments)
		dialog.SetLicense(license)
		dialog.SetWrapLicense(true)
		dialog.Run()
		dialog.Destroy()
	},
		nil)
	filesubmenu.Append(exitmenuitem)

	//--------------------------------------------------------
	// GtkVPaned
	//--------------------------------------------------------
	vpaned := gtk.VPaned()
	vbox.Add(vpaned)

	//--------------------------------------------------------
	// GtkFrame
	//--------------------------------------------------------
	frame1 := gtk.Frame(title)
	framebox1 := gtk.VBox(false, 1)
	frame1.Add(framebox1)

	frame2 := gtk.Frame("no image")
	framebox2 := gtk.VBox(false, 1)
	frame2.Add(framebox2)

	vpaned.Add1(frame1)
	vpaned.Add2(frame2)

	//--------------------------------------------------------
	// GtkComboBox
	//--------------------------------------------------------
	lastsignal := 0
	configuration := 0
	controls := gtk.HBox(false, 1)
	var combotext *gtk.GtkLabel
	var combobox *gtk.GtkComboBox
	togglebutton := gtk.ToggleButtonWithLabel("Start capture")
	togglebutton.Connect("toggled", func() {
		if togglebutton.GetActive() {
			combotext.Hide()
			combobox.Hide()
			togglebutton.SetLabel("Stop capture")
		} else {
			combotext.Show()
			combobox.Show()
			togglebutton.SetLabel("Start capture")
		}
	},
		nil)
	controls.Add(togglebutton)
	combotext = gtk.Label("Choose an astronomical object: ")
	controls.Add(combotext)
	combobox = gtk.ComboBoxNewText()
	for i:=0; i<len(imgs.dirs); i++ {
		combobox.AppendText(path.Base(imgs.dirs[i]))
	}
	combobox.SetActive(0)
	combobox.Connect("changed", func() {
		if !togglebutton.GetActive() {
			selected := combobox.GetActiveText()
			for _, v := range imgs.bufs {
				v.Hide()
				framebox2.Remove(v)
			}
			err = imgs.chooseImagesDir(path.Join(imagesPath, selected))
			if err != nil {
				log.Exit(err)
			}
			frame2.SetLabel(selected)
			for _, v := range imgs.bufs {
				framebox2.Add(v)
			}
			configuration = signaltoconf[lastsignal]
			imgs.visible = imgs.bufs[configuration - 1]
//			imgs.visible = imgs.bufs[0]
			imgs.visible.Show()
		}
	}, nil)
	controls.Add(combobox)
	framebox1.PackStart(controls, false, false, 0)

	//--------------------------------------------------------
	// show it!
	//--------------------------------------------------------
	window.Add(vbox)
//TODO: resize with the size of the image
	window.SetSizeRequest(600, 600)
	window.ShowAll()
	// add first series of images
	for i := 0; i<len(imgs.paths); i++ {
		framebox2.Add(imgs.bufs[i])
	}
	frame2.SetLabel(path.Base(imgs.dir))
	imgs.visible = imgs.bufs[0]
	imgs.visible.Show()

	//--------------------------------------------------------
	// listen for signal from the other (i.e labview) program
	//--------------------------------------------------------
	go func() {
		counter := 0
		for {
			signal := <-c
			if togglebutton.GetActive() {
				if signal != lastsignal {
					configuration = signaltoconf[signal]
					if configuration == 0  {
						log.Stderrf("Unknown signal: %d \n", signal)
						continue
					}
					imgs.visible.Hide()
					imgs.visible = imgs.bufs[configuration-1]
					imgs.visible.Show()
					lastsignal = signal
					counter++
					log.Stdoutf("counter: %d \n", counter)
				}
			}
		}
	}()
	gtk.Main()
}

func main() {
	c1 := make(chan int)  
	c2 := make(chan int)  
	go gtkStuff(c1)
	go readSignal(c2)
	for {
		foo := <- c2
		c1 <- foo
	}

}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.