-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #74 from jopbrown/update-7guis
update examples/7GUIs
- Loading branch information
Showing
30 changed files
with
1,020 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# 7GUIs examples | ||
|
||
These are examples of implementing [7GUIs](https://eugenkiss.github.io/7guis/). | ||
|
||
The implementation heavily references: | ||
1. [7guis-fltk-rs](https://github.com/tdryer/7guis-fltk-rs) | ||
2. [7GUIs Implementation in IUP](https://www.tecgraf.puc-rio.br/iup/en/7gui/7gui.html) | ||
|
||
## Counter | ||
|
||
![screenshot](counter/screenshot.png) | ||
|
||
## Temperature Converter | ||
|
||
![screenshot](temperature/screenshot.png) | ||
|
||
## Flight Booker | ||
|
||
![one way flight](flightbooker/screenshot1.png) | ||
![abnormal](flightbooker/screenshot2.png) | ||
![return flight](flightbooker/screenshot3.png) | ||
|
||
## Timer | ||
|
||
![screenshot](timer/screenshot.png) | ||
|
||
## CRUD | ||
|
||
![screenshot](crud/screenshot.png) | ||
|
||
## Circle Drawer | ||
|
||
![screenshot](circle/screenshot.png) | ||
|
||
## Cells | ||
|
||
> only implement the `SUM()` formula. | ||
![screenshot](cells/screenshot.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"math" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
var reSumFormula = regexp.MustCompile(`(?i)SUM\(([A-Z]\d+):([A-Z]\d+)\)`) | ||
|
||
type Context struct { | ||
Cells [][]*Cell | ||
} | ||
|
||
func NewContext(maxRow, maxCol int) *Context { | ||
ctx := &Context{} | ||
ctx.Cells = make([][]*Cell, maxRow) | ||
for row := range ctx.Cells { | ||
ctx.Cells[row] = make([]*Cell, maxCol) | ||
for col := range ctx.Cells[row] { | ||
cell := &Cell{} | ||
cell.Loc.Row = CellRow(row) | ||
cell.Loc.Col = CellCol(col) | ||
cell.Data = &CellDataText{} | ||
ctx.Cells[row][col] = cell | ||
} | ||
} | ||
|
||
return ctx | ||
} | ||
|
||
func (ctx *Context) FindCell(loc CellLoc) *Cell { | ||
if int(loc.Row) >= len(ctx.Cells) || int(loc.Col) >= len(ctx.Cells[loc.Row]) { | ||
return nil | ||
} | ||
return ctx.Cells[loc.Row][loc.Col] | ||
} | ||
|
||
func ParseCellData(value string) CellData { | ||
if strings.HasPrefix(value, "=") { | ||
formula := value[1:] | ||
matches := reSumFormula.FindStringSubmatch(formula) | ||
if matches == nil { | ||
return &CellDataInvalid{Reason: "SUPPORT FORMULA"} | ||
} | ||
|
||
strStartLoc := matches[1] | ||
startLoc, err := ParseCellLoc(strStartLoc) | ||
if err != nil { | ||
return &CellDataInvalid{Reason: "INVALID START CELL"} | ||
} | ||
|
||
strEndLoc := matches[2] | ||
endLoc, err := ParseCellLoc(strEndLoc) | ||
if err != nil { | ||
return &CellDataInvalid{Reason: "INVALID END CELL"} | ||
} | ||
|
||
formulaData := &CellDataFormula{} | ||
formulaData.Formula = formula | ||
formulaData.CalCells = make(map[CellLoc]*Cell) | ||
for row := startLoc.Row; row <= endLoc.Row; row++ { | ||
for col := startLoc.Col; col <= endLoc.Col; col++ { | ||
loc := CellLoc{Row: row, Col: col} | ||
formulaData.CalCells[loc] = ctx.FindCell(loc) | ||
} | ||
} | ||
return formulaData | ||
} | ||
|
||
num, err := strconv.ParseFloat(value, 64) | ||
if err == nil { | ||
return &CellDataNumber{Number: num} | ||
} | ||
|
||
return &CellDataText{Text: value} | ||
} | ||
|
||
func (cell *Cell) Update(value string) { | ||
cellData := ParseCellData(value) | ||
cell.Data = cellData | ||
cell.RawValue = value | ||
} | ||
|
||
func (ctx *Context) FindAllChangedCells(cell *Cell) map[CellLoc]*Cell { | ||
changedCells := make(map[CellLoc]*Cell) | ||
changedCells[cell.Loc] = cell | ||
|
||
ctx.findAllChangedCells(cell, changedCells) | ||
|
||
return changedCells | ||
} | ||
|
||
func (ctx *Context) findAllChangedCells(cell *Cell, changedCells map[CellLoc]*Cell) { | ||
for row := range ctx.Cells { | ||
for col := range ctx.Cells[row] { | ||
changedCell := ctx.Cells[row][col] | ||
if changedCell.Data.IsDependOn(cell) { | ||
if _, exist := changedCells[changedCell.Loc]; !exist { | ||
changedCells[changedCell.Loc] = changedCell | ||
ctx.findAllChangedCells(changedCell, changedCells) | ||
} else { | ||
changedCell.Data = &CellDataInvalid{Reason: "RECURSIVE FORMULA"} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (ctx *Context) UpdateCellAtLoc(locStr string, value string) { | ||
loc, err := ParseCellLoc(locStr) | ||
if err != nil { | ||
return | ||
} | ||
cell := ctx.FindCell(loc) | ||
if cell == nil { | ||
return | ||
} | ||
cell.Update(value) | ||
} | ||
|
||
type Cell struct { | ||
Loc CellLoc | ||
Data CellData | ||
RawValue string | ||
} | ||
|
||
type CellRow int | ||
|
||
func (row CellRow) String() string { | ||
return strconv.Itoa(int(row)) | ||
} | ||
|
||
type CellCol int | ||
|
||
func (col CellCol) String() string { | ||
return string('A' + byte(col)) | ||
} | ||
|
||
type CellLoc struct { | ||
Row CellRow | ||
Col CellCol | ||
} | ||
|
||
func (loc CellLoc) String() string { | ||
return loc.Col.String() + loc.Row.String() | ||
} | ||
|
||
var ZERO_CELL_LOC = CellLoc{0, 0} | ||
|
||
func ParseCellLoc(str string) (CellLoc, error) { | ||
loc := ZERO_CELL_LOC | ||
|
||
if len(str) < 2 { | ||
return loc, errors.New("invalid cell location: len(str) < 2") | ||
} | ||
|
||
str = strings.ToUpper(str) | ||
|
||
runeCol := str[0] | ||
if runeCol > 'Z' || runeCol < 'A' { | ||
return ZERO_CELL_LOC, fmt.Errorf("invalid cell column: '%c'", runeCol) | ||
} | ||
loc.Col = CellCol(runeCol - 'A') | ||
|
||
strRow := str[1:] | ||
irow, err := strconv.Atoi(strRow) | ||
if err != nil { | ||
return ZERO_CELL_LOC, fmt.Errorf("invalid cell row: '%s'", strRow) | ||
} | ||
loc.Row = CellRow(irow) | ||
|
||
return loc, nil | ||
} | ||
|
||
type CellData interface { | ||
Eval() float64 | ||
Display() string | ||
IsDependOn(cell *Cell) bool | ||
} | ||
|
||
type CellDataNumber struct { | ||
Number float64 | ||
} | ||
|
||
func (data *CellDataNumber) Eval() float64 { | ||
return data.Number | ||
} | ||
|
||
func (data *CellDataNumber) Display() string { | ||
return fmt.Sprintf("%f", data.Number) | ||
} | ||
|
||
func (data *CellDataNumber) IsDependOn(cell *Cell) bool { | ||
return false | ||
} | ||
|
||
type CellDataFormula struct { | ||
Formula string | ||
CalCells map[CellLoc]*Cell | ||
} | ||
|
||
func (data *CellDataFormula) Eval() float64 { | ||
sum := 0.0 | ||
for _, calCell := range data.CalCells { | ||
if calCell != nil { | ||
sum += calCell.Data.Eval() | ||
} | ||
} | ||
return sum | ||
} | ||
|
||
func (data *CellDataFormula) Display() string { | ||
num := data.Eval() | ||
return fmt.Sprintf("%f", num) | ||
} | ||
|
||
func (data *CellDataFormula) IsDependOn(cell *Cell) bool { | ||
_, ok := data.CalCells[cell.Loc] | ||
return ok | ||
} | ||
|
||
type CellDataInvalid struct { | ||
Reason string | ||
} | ||
|
||
func (data *CellDataInvalid) Eval() float64 { | ||
return math.NaN() | ||
} | ||
|
||
func (data *CellDataInvalid) Display() string { | ||
return data.Reason | ||
} | ||
|
||
func (data *CellDataInvalid) IsDependOn(cell *Cell) bool { | ||
return false | ||
} | ||
|
||
type CellDataText struct { | ||
Text string | ||
} | ||
|
||
func (data *CellDataText) Eval() float64 { | ||
return 0.0 | ||
} | ||
|
||
func (data *CellDataText) Display() string { | ||
return data.Text | ||
} | ||
|
||
func (data *CellDataText) IsDependOn(cell *Cell) bool { | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/pwiecz/go-fltk" | ||
) | ||
|
||
const ( | ||
WIDGET_HEIGHT = 200 | ||
WIDGET_WIDTH = 450 | ||
) | ||
|
||
const ( | ||
MAX_ROW_COUNT = 100 // 0~99 | ||
MAX_COL_COUNT = 26 // A~Z | ||
) | ||
|
||
var ctx = NewContext(MAX_ROW_COUNT, MAX_COL_COUNT) | ||
|
||
func init() { | ||
ctx.UpdateCellAtLoc("B1", "5") | ||
ctx.UpdateCellAtLoc("B2", "1") | ||
ctx.UpdateCellAtLoc("B3", "10.3") | ||
ctx.UpdateCellAtLoc("B4", "22.87") | ||
ctx.UpdateCellAtLoc("B5", "=SUM(B1:B4)") | ||
ctx.UpdateCellAtLoc("C1", "6") | ||
ctx.UpdateCellAtLoc("C2", "7") | ||
ctx.UpdateCellAtLoc("C3", "2") | ||
ctx.UpdateCellAtLoc("C4", "5") | ||
ctx.UpdateCellAtLoc("C5", "=SUM(C1:C4)") | ||
ctx.UpdateCellAtLoc("A5", "Sum") | ||
ctx.UpdateCellAtLoc("D5", "=SUM(B5:C5)") | ||
} | ||
|
||
func main() { | ||
fltk.SetScheme("gtk+") | ||
|
||
win := fltk.NewWindow( | ||
WIDGET_WIDTH, | ||
WIDGET_HEIGHT) | ||
win.SetLabel("Cells") | ||
|
||
p := NewPanel(win, MAX_ROW_COUNT, MAX_COL_COUNT) | ||
p.Bind(ctx) | ||
|
||
win.End() | ||
win.Show() | ||
fltk.Run() | ||
} |
Oops, something went wrong.