How To > Develop a Bitmap Painting Tool- Load and Save |
In this step of the Bitmap Painting tool development, we will add a main menu bar with New, Open and Save options.
NATURAL LANGUAGE |
We will define a new right-click menu with some menu items and corresponding event handlers |
We will assign the right-click menu as menu bar to the dialog. |
--Code in italic has not changes since the previous version! macroScript MicroPaint category:"HowTo" ( global MicroPaint_CanvasRollout try(destroyDialog MicroPaint_CanvasRollout)catch() local isDrawing = false local bitmapX = bitmapY = 512 local theCanvasBitmap = bitmap bitmapX bitmapY color:white local theBackgroundBitmap = bitmap bitmapX bitmapY color:white
We will define a second bitmap called background. It will not be used yet, but will be needed in the next tutorial to allow for an eraser function!
This is a right-click menu definition.
The first item in the menu will be called File. A typical program implements File, Edit and Help items in its main menu, we will defined these, too.
Inside the File menu, we will add some menu items to start a new drawing, open an existing one and saving the results to a file on disk.
This is a separator which draws a horizontal line between the menu items.
This menu item will be used to quit the tool.
We will leave the Edit menu empty for now...
The Help menu will contain only the about item.
This is the event handler of the File>New menu item. If the user selected it from the menu...
theBackgroundBitmap = theCanvasBitmap = bitmap bitmapX bitmapY color:MicroPaint_CanvasRollout.paperColor.color
...we will define a new bitmap using the new paper color (background color) added to the User Interface, and will assign to the painting canvas and the new background bitmap.
Then, we assign the result to the User Interface bitmap.
This is the event handler of the File>Open menu item. If the user selected it from the menu...
...we open the standard Bitmap picker dialog of 3dsmax. It provides options to preview all supported file formats.
If the user picked a valid bitmap and did not cancel out...
...we copy the bitmap that was opened into the painting canvas...
...and into the background bitmap. The copy method resizes the original to fit the size of the canvas!
Finally, we close the opened bitmap...
...and assign the painting canvas to the User Interface bitmap.
This is the event handler of the File>Save As... menu item. If the user selected it from the menu...
...we open the standard file saving dialog of3ds Maxand provide a list of some file extensions. (You can add any supported file formats like RLA, RPF etc. to this list).
If the user specified a valid name and did not cancel out...
...we set the file name of the painting canvas to the selected name...
...and save the bitmap to disk.
If the user picked the Help>About menu item, we open a message box with some text. You can add your own text to this dialog with version number etc....
If the user picked the File>Quit menu item, we destroy the dialog. In the future, we could add a prompt whether the current painting should be saved to disk...
) rollout MicroPaint_CanvasRollout "MicroPaint" ( bitmap theCanvas pos:[0,0] width:bitmapX height:bitmapY bitmap:theCanvasBitmap colorpicker inkColor height:16modal:false color:black across:5
To add the paper color (background color of new images), we have to increase the across: parameter to 5.
This colorpicker adds the paper color (background color of new images). Note that the color pickers are modeless and can be kept open all the time. You can also drag and drop colors to copy colors between the Ink and Paper color pickers, or drag and drop from other areas of 3ds Max!
checkbutton airBrush "AirBrush" width:50 spinner AirBrushSpeed "Speed" range:[0.1,50,10] fieldwidth:30 spinner BrushSize "Size" range:[1,50,10] type:#integer fieldwidth:40 listbox BrushShape items:#("Circle", "Box", "Circle Smooth") pos:[bitmapX+5,0] width:90 fn paintBrush pos = ( case BrushShape.selection of ( 1: ( if distance pos currentPos <= BrushSize.value/2 do setPixels theCanvasBitmap pos #(inkColor.color) ) 2: setPixels theCanvasBitmap pos #(inkColor.color) 3: ( theFactor = (distance pos currentPos) / (BrushSize.value/2.0) if theFactor <= 1.0 do ( theFactor = sin ( 90.0 * theFactor) thePixels = getPixels theCanvasBitmap pos 1 if thePixels[1] != undefined do ( thePixels[1] = (thePixels[1] * theFactor) + (inkColor.color * (1.0 - theFactor)) setPixels theCanvasBitmap pos thePixels ) ) )--end case 3 )--end case )--end fn fn drawStroke lastPos pos = ( currentPos = lastPos deltaX = pos.x - lastPos.x deltaY = pos.y - lastPos.y maxSteps = amax #(abs(deltaX),abs(deltaY)) deltaStepX = deltaX / maxSteps deltaStepY = deltaY / maxSteps for i = 0 to maxSteps do ( if airBrush.checked then ( for b = 1 to (BrushSize.value / AirBrushSpeed.value) do paintBrush (currentPos + (random [-BrushSize.value/2,-BrushSize.value/2] [BrushSize.value/2,BrushSize.value/2] )) ) else for b = -BrushSize.value/2 to BrushSize.value/2 do for c = -BrushSize.value/2 to BrushSize.value/2 do paintBrush (currentPos + [c,b]) currentPos += [deltaStepX, deltaStepY] ) theCanvas.bitmap = theCanvasBitmap ) on MicroPaint_CanvasRollout lbuttondown pos do ( lastPos = pos isDrawing = true drawStroke lastPos pos ) on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false on MicroPaint_CanvasRollout mousemove pos do ( if isDrawing do drawStroke lastPos pos lastPos = pos ) ) createDialog MicroPaint_CanvasRollout (bitmapx+100) (bitmapy+30) menu:CanvasMenu
We add the RightClick menu defined in the beginning of the script to the dialog.
After starting the tool, it is a good idea to clear the display, as the bitmap might be still displaying an older version from a previous painting session.