I've been playing with B4A by creating a little kaleidoscope app - you draw on the screen, and it mirrors your drawing in various ways.
I tried adding an Undo function, so you can undo your last stroke. Trouble is, I can't get it working right, so maybe someone here with more B4A kung fu can spot the problem.
Basically, it works like this:
- All drawing is done on a canvas initialized from a panel. (That part works.)
- On touch-down, I copy the canvas bitmap to a second bitmap.
- On touch-move, I do the drawing.
- On touch-up, I enable the Undo button.
- The Undo button draws the second bitmap back onto the canvas.
All this works (apparently), except for the last action - clicking Undo does not visibly affect the canvas bitmap.
Excerpted code attached here for your viewing pleasure. Any help GREATLY appreciated.
I tried adding an Undo function, so you can undo your last stroke. Trouble is, I can't get it working right, so maybe someone here with more B4A kung fu can spot the problem.
Basically, it works like this:
- All drawing is done on a canvas initialized from a panel. (That part works.)
- On touch-down, I copy the canvas bitmap to a second bitmap.
- On touch-move, I do the drawing.
- On touch-up, I enable the Undo button.
- The Undo button draws the second bitmap back onto the canvas.
All this works (apparently), except for the last action - clicking Undo does not visibly affect the canvas bitmap.
Excerpted code attached here for your viewing pleasure. Any help GREATLY appreciated.
B4X:
Sub Process_Globals
Dim penColor As Int : penColor = Colors.Red
Dim penWidth As Int : penWidth = 5
Dim mirrorNumber As Int : mirrorNumber = 7 'default to all mirrors
Dim oldX, oldY As Float
Dim screenHalfX, screenHalfY As Float
Dim panelRect As Rect
Dim preserveBitmap, undoBitmap As Bitmap
End Sub
Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim drawingPanel As Panel
Dim panelCanvas As Canvas
Dim clearButton As Button
Dim colorButton As Button
Dim horizontalToggle As ToggleButton
Dim slashToggle As ToggleButton
Dim verticalToggle As ToggleButton
Dim widthSeek As SeekBar
Dim widthLabel As Label
Dim backSlashToggle As ToggleButton
Dim mirrorSpinner As Spinner
Dim undoButton As Button
End Sub
Sub Activity_Create(FirstTime As Boolean)
activity.LoadLayout("main")
If activity.Height > activity.Width Then 'portrait
drawingPanel.Width = activity.Width
Else 'landscape 800x480
drawingPanel.Width = activity.height
drawingPanel.Left = activity.Width - drawingPanel.Width 'flush right
mirrorSpinner.Width = drawingPanel.Left - 7 - mirrorSpinner.Left 'stretch to fit
widthSeek.Width = drawingPanel.Left - 10 - widthSeek.Left 'stretch to fit
undoButton.Width = drawingPanel.Left - 7 - undoButton.Left 'stretch to fit
clearButton.Width = drawingPanel.Left - 7 - clearButton.Left 'stretch to fit
End If
drawingPanel.Height = drawingPanel.Width 'for now, keep it square
If FirstTime Then
preserveBitmap.InitializeMutable(drawingPanel.Width, drawingPanel.Height) 'preserve it on subsequent creations
undoBitmap.InitializeMutable(drawingPanel.Width, drawingPanel.Height)
drawingPanel.Color = Colors.Black
End If
panelCanvas.Initialize(drawingPanel)
colorButton.Color = penColor
widthSeek.Value = penWidth - .99
screenHalfX = drawingPanel.Width / 2
screenHalfY = drawingPanel.Width / 2
mirrorSpinner.AddAll(Array As String("No mirrors", "Vertical mirror", "Horizontal mirror", "Vert. & horiz. mirrors", "Right diagonal mirror", "Left diagonal mirror", "Both diagonal mirrors", "All mirrors!"))
mirrorSpinner.SelectedIndex = mirrorNumber 'set to last item (all mirrors)
panelRect.Initialize(0, 0, panelCanvas.Bitmap.Width, panelCanvas.Bitmap.Height)
panelCanvas.DrawBitmap(preserveBitmap, Null, panelRect) 'restore the existing bitmap, if any
End Sub
Sub Activity_Pause (UserClosed As Boolean)
preserveBitmap = panelCanvas.Bitmap 'preserve existing drawing
End Sub
Sub drawingPanel_Touch (Action As Int, X As Float, Y As Float)
If Action = activity.ACTION_DOWN Then 'start a new line
undoBitmap = panelCanvas.Bitmap 'save existing drawing for possible Undo
oldX = x
oldY = y
Else If Action = activity.ACTION_MOVE Then 'continue the current line
panelCanvas.DrawLine(oldX, oldY, x, y, penColor, penWidth)
Select mirrorSpinner.SelectedIndex
Case 1 : drawVerticalMirror(oldX, oldY, x, y)
Case 2 : drawHorizontalMirror(oldX, oldY, x, y)
Case 3 : drawVertHorizMirrors(oldX, oldY, x, y)
Case 4 : drawSlashMirror(oldX, oldY, x, y)
Case 5 : drawBackSlashMirror(oldX, oldY, x, y)
Case 6 : drawDiagonalMirrors(oldX, oldY, x, y)
Case 7 : 'all mirrors
drawVertHorizMirrors(oldX, oldY, x, y)
drawDiagonalMirrors(oldX, oldY, x, y)
drawDiagonalMirrors(mirrorVertical(oldX), oldY, mirrorVertical(x), y)
End Select
drawingPanel.Invalidate
oldX = x
oldY = y
Else 'action up - end the line
undoButton.Enabled = True
End If
End Sub
Sub mirrorVertical(argX As Float)
Return (screenHalfX - argX) + screenHalfX
End Sub
...
Sub undoButton_Click
panelCanvas.DrawBitmap(undoBitmap, Null, panelRect)
drawingPanel.Invalidate
undoButton.Enabled = False
End Sub