diff --git a/pkg/doodads/fmt_readwrite.go b/pkg/doodads/fmt_readwrite.go index 1666350..6406e7f 100644 --- a/pkg/doodads/fmt_readwrite.go +++ b/pkg/doodads/fmt_readwrite.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "runtime" + "sort" "strings" "git.kirsle.net/apps/doodle/pkg/bindata" @@ -57,6 +58,8 @@ func ListDoodads() ([]string, error) { } } + sort.Strings(result) + return result, err } diff --git a/pkg/editor_scene.go b/pkg/editor_scene.go index 3daab4b..c50f8f0 100644 --- a/pkg/editor_scene.go +++ b/pkg/editor_scene.go @@ -174,12 +174,15 @@ func (s *EditorScene) Loop(d *Doodle, ev *events.State) error { case "l": d.Flash("Line Tool selected.") s.UI.Canvas.Tool = drawtool.LineTool + s.UI.activeTool = s.UI.Canvas.Tool.String() case "f": d.Flash("Pencil Tool selected.") s.UI.Canvas.Tool = drawtool.PencilTool + s.UI.activeTool = s.UI.Canvas.Tool.String() case "r": d.Flash("Rectangle Tool selected.") s.UI.Canvas.Tool = drawtool.RectTool + s.UI.activeTool = s.UI.Canvas.Tool.String() } return nil diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index 04e9d22..258437d 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -49,8 +49,15 @@ type EditorUI struct { PaletteTab *ui.Frame DoodadTab *ui.Frame + // Doodad Palette window variables. + doodadSkip int + doodadRows []*ui.Frame + doodadPager *ui.Frame + doodadButtonSize int32 + doodadScroller *ui.Frame + // ToolBar window. - activeTool *string + activeTool string // Draggable Doodad canvas. DraggableActor *DraggableActor @@ -72,8 +79,7 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI { } // Default tool in the toolbox. - activeTool := drawtool.PencilTool.String() - u.activeTool = &activeTool + u.activeTool = drawtool.PencilTool.String() // Bind the StatusBoxes arrays to the text variables. u.StatusBoxes = []*string{ @@ -154,6 +160,8 @@ func (u *EditorUI) Resized(d *Doodle) { u.MenuBar.BoxSize().H, )) u.Palette.Compute(d.Engine) + + u.scrollDoodadFrame(0) } var innerHeight = int32(u.d.height) - u.MenuBar.Size().H - u.StatusBar.Size().H diff --git a/pkg/editor_ui_doodad.go b/pkg/editor_ui_doodad.go index 790b628..29fd806 100644 --- a/pkg/editor_ui_doodad.go +++ b/pkg/editor_ui_doodad.go @@ -49,8 +49,6 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra perRow = balance.UIDoodadsPerRow ) - frame.SetBackground(render.RGBA(0, 153, 255, 153)) - // Pager buttons on top of the doodad list. pager := ui.NewFrame("Doodad Pager") pager.SetBackground(render.RGBA(255, 0, 0, 20)) // TODO: if I don't set a background color, @@ -59,28 +57,40 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra { leftBtn := ui.NewButton("Prev Page", ui.NewLabel(ui.Label{ Text: "<", + Font: balance.MenuFont, })) + leftBtn.Handle(ui.Click, func(p render.Point) { + u.scrollDoodadFrame(-1) + }) u.Supervisor.Add(leftBtn) pager.Pack(leftBtn, ui.Pack{ Anchor: ui.W, }) - pageLabel := ui.NewLabel(ui.Label{ - Text: " Page 1 of 20", + scroller := ui.NewFrame("Doodad Scroll Progressbar") + scroller.Configure(ui.Config{ + Width: 20, + Height: 20, + Background: render.RGBA(128, 128, 128, 128), }) - pager.Pack(pageLabel, ui.Pack{ + pager.Pack(scroller, ui.Pack{ Anchor: ui.W, - Expand: true, }) + u.doodadScroller = scroller rightBtn := ui.NewButton("Next Page", ui.NewLabel(ui.Label{ Text: ">", + Font: balance.MenuFont, })) + rightBtn.Handle(ui.Click, func(p render.Point) { + u.scrollDoodadFrame(1) + }) u.Supervisor.Add(rightBtn) pager.Pack(rightBtn, ui.Pack{ - Anchor: ui.W, + Anchor: ui.E, }) } + u.doodadPager = pager frame.Pack(pager, ui.Pack{ Anchor: ui.N, Fill: true, @@ -96,64 +106,138 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra } var buttonSize = (paletteWidth - window.BoxThickness(2)) / int32(perRow) + u.doodadButtonSize = buttonSize // Draw the doodad buttons in a grid `perRow` buttons wide. var ( row *ui.Frame - rowCount int // for labeling the ui.Frame for each row + rowCount int // for labeling the ui.Frame for each row + btnRows = []*ui.Frame{} // Collect the row frames for the buttons. ) for i, filename := range doodadsAvailable { + filename := filename + if row == nil || i%perRow == 0 { rowCount++ row = ui.NewFrame(fmt.Sprintf("Doodad Row %d", rowCount)) row.SetBackground(balance.WindowBackground) + btnRows = append(btnRows, row) frame.Pack(row, ui.Pack{ Anchor: ui.N, Fill: true, }) } - func(filename string) { - doodad, err := doodads.LoadFile(filename) - if err != nil { - log.Error(err.Error()) - doodad = doodads.New(balance.DoodadSize) - } + doodad, err := doodads.LoadFile(filename) + if err != nil { + log.Error(err.Error()) + doodad = doodads.New(balance.DoodadSize) + } - can := uix.NewCanvas(int(buttonSize), true) - can.Name = filename - can.SetBackground(render.White) - can.LoadDoodad(doodad) + can := uix.NewCanvas(int(buttonSize), true) + can.Name = filename + can.SetBackground(render.White) + can.LoadDoodad(doodad) - btn := ui.NewButton(filename, can) - btn.Resize(render.NewRect( - buttonSize-2, // TODO: without the -2 the button border - buttonSize-2, // rests on top of the window border. - )) - row.Pack(btn, ui.Pack{ - Anchor: ui.W, - }) + btn := ui.NewButton(filename, can) + btn.Resize(render.NewRect( + buttonSize-2, // TODO: without the -2 the button border + buttonSize-2, // rests on top of the window border. + )) + row.Pack(btn, ui.Pack{ + Anchor: ui.W, + }) - // Begin the drag event to grab this Doodad. - // NOTE: The drag target is the EditorUI.Canvas in - // editor_ui.go#SetupCanvas() - btn.Handle(ui.MouseDown, func(e render.Point) { - log.Warn("MouseDown on doodad %s (%s)", doodad.Filename, doodad.Title) - u.startDragActor(doodad) - }) - u.Supervisor.Add(btn) + // Begin the drag event to grab this Doodad. + // NOTE: The drag target is the EditorUI.Canvas in + // editor_ui.go#SetupCanvas() + btn.Handle(ui.MouseDown, func(e render.Point) { + log.Warn("MouseDown on doodad %s (%s)", doodad.Filename, doodad.Title) + u.startDragActor(doodad) + }) + u.Supervisor.Add(btn) - // Resize the canvas to fill the button interior. - btnSize := btn.Size() - can.Resize(render.NewRect( - btnSize.W-btn.BoxThickness(2), - btnSize.H-btn.BoxThickness(2), - ), - ) + // Resize the canvas to fill the button interior. + btnSize := btn.Size() + can.Resize(render.NewRect( + btnSize.W-btn.BoxThickness(2), + btnSize.H-btn.BoxThickness(2), + ), + ) - btn.Compute(e) - }(filename) + btn.Compute(e) } + u.doodadRows = btnRows + u.scrollDoodadFrame(0) + return frame, nil } + +// scrollDoodadFrame handles the Page Up/Down buttons to adjust the number of +// Doodads visible on screen. +// +// rows is the number of rows to scroll. Positive values mean scroll *down* +// the list. +func (u *EditorUI) scrollDoodadFrame(rows int) { + u.doodadSkip += rows + if u.doodadSkip < 0 { + u.doodadSkip = 0 + } + + log.Info("scrollDoodadFrame(%d): skip=%d", rows, u.doodadSkip) + + // Calculate about how many rows we can see given our current window size. + var ( + maxVisibleHeight = int32(u.d.height - 86) + calculatedHeight int32 + rowsBefore int // count of rows hidden before + rowsVisible int + rowsAfter int // count of rows hidden after + rowsEstimated = maxVisibleHeight / u.doodadButtonSize // estimated number rows shown + maxSkip = ((len(u.doodadRows) * int(u.doodadButtonSize)) - int(u.doodadButtonSize*rowsEstimated)) / int(u.doodadButtonSize) + ) + + if maxSkip < 0 { + maxSkip = 0 + } + + log.Info("maxSkip = (%d * %d) - (%d * %d) = %d", len(u.doodadRows), u.doodadButtonSize, u.doodadButtonSize, rowsEstimated, maxSkip) + // log.Info("maxSkip: estimate=%d rows=%d - visible=%d => %d", rowsEstimated, len(u.doodadRows), rowsVisible, maxSkip) + if u.doodadSkip > maxSkip { + u.doodadSkip = maxSkip + } + + // If the window is big enough to encompass all the doodads, don't show + // the pager toolbar, its just confusing. + if maxSkip == 0 { + u.doodadPager.Hide() + } else { + u.doodadPager.Show() + } + + // Comb through the doodads and show/hide the relevant buttons. + for i, row := range u.doodadRows { + if i < u.doodadSkip { + row.Hide() + rowsBefore++ + continue + } + + calculatedHeight += u.doodadButtonSize + if calculatedHeight > maxVisibleHeight { + row.Hide() + rowsAfter++ + } else { + row.Show() + rowsVisible++ + } + } + + var viewPercent = float64(rowsBefore+rowsVisible) / float64(len(u.doodadRows)) + u.doodadScroller.Configure(ui.Config{ + Width: int32(float64(paletteWidth-50) * viewPercent), // TODO: hacky magic number + }) + log.Info("v%% = (%d + %d) / %d = %f", rowsBefore, rowsVisible, len(u.doodadRows), viewPercent) + +} diff --git a/pkg/editor_ui_toolbar.go b/pkg/editor_ui_toolbar.go index 5fe59d1..05f5f94 100644 --- a/pkg/editor_ui_toolbar.go +++ b/pkg/editor_ui_toolbar.go @@ -97,7 +97,7 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { btn := ui.NewRadioButton( button.Value, - u.activeTool, + &u.activeTool, button.Value, image, )