home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / iconed1a / iconwrks.bas < prev    next >
Encoding:
BASIC Source File  |  1995-04-26  |  36.9 KB  |  1,013 lines

  1. Attribute VB_Name = "Module2"
  2. Option Explicit
  3. #If Win32 Then
  4.     DefLng H-I 'h=handle, i = sysint
  5. #Else
  6.     DefInt H-I
  7. #End If
  8. Dim HelpFilePath As String
  9.  
  10. ' When either the Editor's colorpalette or the ColorPalette Forms
  11. ' ColorPalette need repainting, this routine is called, passing in
  12. ' the picture control used for the specific colorpalette.
  13. '
  14. Sub Display_Color_Palette(Pic_ColorPalette As Control)
  15. Dim i%
  16.     
  17.     ' The ColorPalettes consist of 3 rows of 16 colors, so to make
  18.     ' is easy to display and to deterine what color is selected when
  19.     ' the ColorPalette is click, we set the Scale of the ColorPalette
  20.     ' to correspond to the number of color rows and columns.
  21.     '
  22.     Pic_ColorPalette.Scale (0, 0)-(16, 3)
  23.  
  24.     ' Display ColorPalette column by column
  25.     '
  26.     For i% = 0 To 15
  27.         '
  28.         ' Display a column of colors
  29.         '
  30.         Pic_ColorPalette.Line (i%, 0)-(i% + 1, 1), Colors(i%), BF
  31.         Pic_ColorPalette.Line (i%, 1)-(i% + 1, 2), Colors(i% + 16), BF
  32.         Pic_ColorPalette.Line (i%, 2)-(i% + 1, 3), Colors(i% + 32), BF
  33.  
  34.         ' Display vertical line to left of current columns to visually
  35.         ' divide the columns, but skip first column, since it is not
  36.         ' needed due to the Border of the color palette.
  37.         '
  38.         If i% Then Pic_ColorPalette.Line (i%, 0)-(i%, 3)
  39.     Next i%
  40.   
  41.     ' Display 2 horizontal lines to visually divide the color rows.
  42.     '
  43.     Pic_ColorPalette.Line (0, 1)-(16, 1)
  44.     Pic_ColorPalette.Line (0, 2)-(16, 2)
  45.  
  46. End Sub
  47.  
  48. ' Displays the entire or any portion of the grid, when the Grid option
  49. ' is active.  The 4 paramaters passed in, X1, Y1, X2, Y2, define the
  50. ' upper left and lower right corners of the area within the maginified
  51. ' Icon that needs the grid displayed.
  52. '
  53. Sub Display_Grid(hDCDest, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer)
  54. Dim DestX As Integer, DestY As Integer, DestWidth As Integer, DestHeight As Integer
  55.     ' The grid is not displayed if the icon is being viewed at normal
  56.     ' size, so check the current value of the scrollbar.
  57.     '
  58.     If Editor.Scrl_Zoom.Value > Editor.Scrl_Zoom.Min Then
  59.         DestX = X1 * PixelSize
  60.         DestY = Y1 * PixelSize
  61.         DestWidth = (X2 - X1 + 1) * PixelSize
  62.         DestHeight = (Y2 - Y1 + 1) * PixelSize
  63.         BitBlt hDCDest, X1 * PixelSize, Y1 * PixelSize, DestWidth, DestHeight, Editor.Pic_Grid.hDC, DestX, DestY, SRCAND
  64.     End If
  65.  
  66. End Sub
  67.  
  68. ' Whenever a new color is selected for either the left or right mouse
  69. ' button, or the StatusArea needs repainting, this routine is called to
  70. ' display the 4 small color squares at the bottom of the StatusArea
  71. ' which are filled with the current colors selected for the mouse buttons.
  72. '
  73. Sub Display_Mouse_Colors()
  74. Dim Middle As Integer, i As Integer, X1 As Integer, X2 As Integer, Y1 As Integer, Y2 As Integer
  75.  
  76.     ' Calculate the center of the Status bar
  77.     '
  78.     Middle = Editor.Pic_StatusArea.ScaleWidth \ 2
  79.  
  80.     ' Display the 4 color squares
  81.     '
  82.     For i = 0 To 3
  83.         '
  84.         ' The squares are centered within the left and right halfs of the
  85.         ' StatusArea, and the width and height are set equal to the Height
  86.         ' of the Option buttons used to select Left/Right or Screen/Inverse
  87.         ' colors, so we calculate the corners of the the Color squares
  88.         ' based on this information.
  89.         '
  90.         X1 = (i Mod 2) * Middle + (Middle - Editor.Opt_Mouse(i \ 2).Height) \ 2
  91.         X2 = X1 + Editor.Opt_Mouse(i \ 2).Height
  92.         Y1 = Editor.Opt_Mouse(i \ 2).Top
  93.         Y2 = Y1 + Editor.Opt_Mouse(i \ 2).Height
  94.  
  95.         ' Draw the color square
  96.         '
  97.         Editor.Pic_StatusArea.Line (X1, Y1)-(X2, Y2), MouseColors(i), BF
  98.  
  99.         ' Draw a black outline around the square
  100.         '
  101.         Editor.Pic_StatusArea.Line (X1, Y1)-(X2, Y2), BLACK, B
  102.     Next i
  103.         
  104.     ' Set the CurrentY value of the StatusArea back to that of the
  105.     ' location where the Mouse Coordinates are displayed, so this
  106.     ' does not have to be done within each MouseMove event of the
  107.     ' Edit area.
  108.     '
  109.     Editor.Pic_StatusArea.CurrentY = Editor.Pic_Icons(5).Top + Editor.Pic_Icons(5).Height + HIGHLIGHT + 1
  110.  
  111. End Sub
  112.  
  113. ' If a selection has been made, is being made, or a selection is
  114. ' being moved, or the Edit area needs repainting while a selection
  115. ' is active, this routine is called to display or redisplay a
  116. ' rectangle around the current selection.
  117. '
  118. Sub Draw_Selection_Rectangle()
  119. Dim XAdjust As Integer, YAdjust As Integer
  120.  
  121.     ' Set drawing mode to INVERSE since this routine also used to erase
  122.     ' the selection rectangle by simply drawing over the currently displayed
  123.     ' rectangle
  124.     '
  125.     Editor.Pic_Edit.DrawMode = INVERSE
  126.  
  127.     ' To distinguish between a selection and a selection that is
  128.     ' being moved, a Dotted line is used for a selection and a solid
  129.     ' line is used for a selection being moved.
  130.     '
  131.     If MovingSelection Then Editor.Pic_Edit.DrawStyle = SOLID Else Editor.Pic_Edit.DrawStyle = DOT
  132.  
  133.     ' To ensure the entire selection rectangle is visible, the rectangle
  134.     ' is adjusted inward 1 pixel from the right and bottom if the selection
  135.     ' contains either the right most column or bottom most row of pixels.
  136.     '
  137.     If X2Region >= PixelSize * 32 Then XAdjust = 1
  138.     If Y2Region >= PixelSize * 32 Then YAdjust = 1
  139.  
  140.     ' Draw the selection rectangle.
  141.     '
  142.     Editor.Pic_Edit.Line (X1Region, Y1Region)-(X2Region - XAdjust, Y2Region - YAdjust), , B
  143.     Editor.Pic_Edit.DrawStyle = SOLID
  144.  
  145. End Sub
  146.  
  147. ' When the currently selected Icon is changed or a new Icon is
  148. ' loaded into the currently selected Icon, the bitmaps that make
  149. ' of the Icons Mask and Image must be extracted and placed into
  150. ' picture controls where they can easily be edited.
  151. '
  152. Sub Extract_Image_And_Mask(Pic_Ctrl As Control)
  153. #If Win32 Then
  154. Dim IPic As IPicture
  155. Dim icoinfo As ICONINFO
  156. Dim PDesc As PICTDESC
  157. Dim hDCWork
  158. Dim hOldWorkBM
  159. Dim hNewBM
  160. Dim hOldMonoBM
  161.     GetIconInfo Pic_Ctrl.Picture, icoinfo
  162.     hDCWork = CreateCompatibleDC(0)
  163.     hNewBM = CreateCompatibleBitmap(Editor.hDC, 32, 32)
  164.     hOldWorkBM = SelectObject(hDCWork, hNewBM)
  165.     hOldMonoBM = SelectObject(hDCMono, icoinfo.hBMMask)
  166.     BitBlt hDCWork, 0, 0, 32, 32, hDCMono, 0, 0, SRCCOPY
  167.     SelectObject hDCMono, hOldMonoBM
  168.     SelectObject hDCWork, hOldWorkBM
  169.     With PDesc
  170.         .cbSizeofstruct = Len(PDesc)
  171.         .picType = PICTYPE_BITMAP
  172.         .Long1 = hNewBM
  173.     End With
  174.     OleCreatePictureIndirect PDesc, IID_IDispatch, 1, IPic
  175.     Editor.Pic_Mask = IPic
  176.     Set IPic = Nothing
  177.     PDesc.Long1 = icoinfo.hBMColor
  178.     OleCreatePictureIndirect PDesc, IID_IDispatch, 1, IPic
  179.     Editor.Pic_Image = IPic
  180.     DeleteObject icoinfo.hBMMask
  181.     DeleteDC hDCWork
  182. #Else
  183. Dim Lpicon As Long
  184.     ' Get pointer to Icon and prevent Windows form moving it.
  185.     '
  186.     Lpicon = GlobalLock(Pic_Ctrl.Picture)
  187.  
  188.     ' Copy the Icons Mask to Monochrome Bitmap, then copy the MonoBitmap
  189.     ' the the Picture control.
  190.     '
  191.     Editor.Pic_Mask.ForeColor = BLACK
  192.     SetBitmapBits hBMMono, 128, Lpicon + 12
  193.     BitBlt Editor.Pic_Mask.hDC, 0, 0, 32, 32, hDCMono, 0, 0, SRCCOPY
  194.  
  195.     ' Copy Icons Image bitmap to Picture control
  196.     '
  197.     SetBitmapBits Editor.Pic_Image.Image, ImageSize, Lpicon + 12 + 128
  198.  
  199.     ' Free icon so Windows is free to move it.
  200.     '
  201.     GlobalUnlock Pic_Ctrl.Picture
  202. #End If
  203. End Sub
  204.  
  205. ' Displays the selected help topic selected from either
  206. ' Editors;' or Viewer's help menu.
  207. '
  208. Sub Get_Help(HelpTopic As Integer)
  209. Dim dummy$
  210.     If HelpTopic = MID_USING_HELP Then
  211.         '
  212.         ' "Using Help" was selected so display the Standard Windows Help
  213.         ' Topic for "Using Help".
  214.         '
  215.         WinHelp Editor.hWnd, dummy$, HELP_HELPONHELP, 0
  216.     Else
  217.         ' A help topic other the "Using help" was selected.
  218.         '
  219.         
  220.          WinHelp Editor.hWnd, HelpFilePath, HELP_CONTEXT, CLng(HelpTopic)
  221.     End If
  222.  
  223. End Sub
  224.  
  225. Function Help_File_In_Path()
  226. Dim Path As String, CurrentDir As String, SemiColon As Integer, Found As Boolean
  227.  
  228.     On Error Resume Next
  229.     CurrentDir = App.Path
  230.     If Right$(CurrentDir, 1) <> "\" Then CurrentDir = CurrentDir + "\"
  231.     If Len(Dir$(CurrentDir + "IconWrks.HLP")) Then
  232.         HelpFilePath = CurrentDir + "IconWrks.HLP"
  233.         App.HelpFile = CurrentDir + "IconWrks.HLP"
  234.         Help_File_In_Path = True
  235.     Else
  236.         Path = Environ$("PATH")
  237.         If Path <> "" Then
  238.             If Right$(Path, 1) <> ";" Then Path = Path + ";"
  239.             SemiColon = InStr(Path, ";")
  240.             Do
  241.                 CurrentDir = Left$(Path, SemiColon - 1)
  242.                 If Right$(CurrentDir, 1) <> "\" Then CurrentDir = CurrentDir + "\"
  243.                 Path = Right$(Path, Len(Path) - SemiColon)
  244.                 SemiColon = InStr(Path, ";")
  245.                 Found = Len(Dir$(CurrentDir & "IconWrks.HLP"))
  246.             Loop While SemiColon And Not Found
  247.             Help_File_In_Path = Found
  248.         End If
  249.     End If
  250.     
  251.     On Error GoTo 0
  252.  
  253. End Function
  254.  
  255. ' The currently selected icon is distinguished by a solid square
  256. ' slightly larger than the icon itself, drawn behind the icon using
  257. ' the currently selected screen color.  This routine is called
  258. ' whenever this square needs to be displayed or redisplayed.
  259. '
  260. Sub HighLight_Current_Icon()
  261. Dim X1 As Integer, X2 As Integer, Y1 As Integer, Y2 As Integer
  262.     ' Erase the current selection square.
  263.     '
  264.     Editor.Pic_StatusArea.Line (0, 0)-(Editor.Pic_StatusArea.Width, Editor.Pic_Icons(4).Top + Editor.Pic_Icons(4).Height + 10), Editor.Pic_StatusArea.BackColor, BF
  265.  
  266.     ' Calculate the upper left and lower right corners of the selection square.
  267.     '
  268.     X1 = Editor.Pic_Icons(CurrentIcon).Left - HIGHLIGHT
  269.     X2 = Editor.Pic_Icons(CurrentIcon).Left + Editor.Pic_Icons(CurrentIcon).Width + HIGHLIGHT
  270.     Y1 = Editor.Pic_Icons(CurrentIcon).Top - HIGHLIGHT
  271.     Y2 = Editor.Pic_Icons(CurrentIcon).Top + Editor.Pic_Icons(CurrentIcon).Height + HIGHLIGHT
  272.   
  273.     ' Draw the solid selection square.
  274.     '
  275.     Editor.Pic_StatusArea.Line (X1, Y1)-(X2, Y2), MouseColors(2), BF
  276.  
  277.     ' Draw a Black outline around the square.
  278.     '
  279.     Editor.Pic_StatusArea.Line (X1, Y1)-(X2, Y2), BLACK, B
  280.  
  281.     If Editor.Menu_ViewSelection(MID_BORDER).Checked Then
  282.         '
  283.         ' Show edge of selected Icon by outline the icon
  284.         '
  285.         X1 = Editor.Pic_Icons(CurrentIcon).Left - 1
  286.         X2 = Editor.Pic_Icons(CurrentIcon).Left + Editor.Pic_Icons(CurrentIcon).Width
  287.         Y1 = Editor.Pic_Icons(CurrentIcon).Top - 1
  288.         Y2 = Editor.Pic_Icons(CurrentIcon).Top + Editor.Pic_Icons(CurrentIcon).Height
  289.         Editor.Pic_StatusArea.Line (X1, Y1)-(X2, Y2), BLACK, B
  290.     End If
  291.     
  292.     ' Set the CurrentY value of the StatusArea back to that of the
  293.     ' location where the Mouse Coordinates are displayed.
  294.     '
  295.     Editor.Pic_StatusArea.CurrentY = Editor.Pic_Icons(5).Top + Editor.Pic_Icons(5).Height + HIGHLIGHT + 1
  296.     
  297. End Sub
  298.  
  299. ' Inverts the specified control when an Icon from the Viewer is being
  300. ' dragged over the top of it, signaling that the Icon may be dropped
  301. ' on this control.
  302. '
  303. Sub Invert_Control(Ctrl As Control)
  304. Dim rectangle As RECT
  305.   
  306.     ' Calculate the Rectangle to invert
  307.     '
  308.     rectangle.Right = Ctrl.ScaleWidth
  309.     rectangle.bottom = Ctrl.ScaleHeight
  310.  
  311.     ' Invert the rectangle
  312.     '
  313.      InvertRect Ctrl.hDC, rectangle
  314.  
  315. End Sub
  316.  
  317. ' This routine is used to tie the Viewer and the Editor together.  When
  318. ' and Icon is selected in one of the various ways from within the Viewer,
  319. ' or an Icon is dragged from the Viewer and dropped on a valid location
  320. ' of the Editor, this routine is called either from the Viewer or from
  321. ' the Editor (depending on how the Icon was selected), to load the
  322. ' selected icon into the Editor.
  323. '
  324. Sub Load_An_Icon()
  325.  
  326.     ' Check if the new icon would be replacing an existing Icon which
  327.     ' has been changed since the last time it has been saved, and if
  328.     ' so, ask the user if it is ok to discard the changes.
  329.     '
  330.     If Ok_To_Discard_Changes() Then
  331.         '
  332.         ' Get the Filename and Fullpath to the icon, and set its
  333.         ' Changed flag to FALSE.
  334.         '
  335.         ICONINFO(CurrentIcon).FileName = Viewer.File_FileList.FileName
  336.         ICONINFO(CurrentIcon).FullPath = Viewer.File_FileList.Path
  337.         ICONINFO(CurrentIcon).Changed = False
  338.  
  339.         ' Place the Name and Path of the Icon in the corresponding menu
  340.         ' item in the Editors Icons menu.
  341.         '
  342.         Editor.Menu_IconsSelection(CurrentIcon).Caption = "&" + Format$(CurrentIcon + 1) + " - [" + Viewer.File_FileList.Path + "]" + A_TAB + Viewer.File_FileList.FileName
  343.  
  344.         ' Load the Icon into the selected icon in the StatusArea.
  345.         '
  346.         Editor.Pic_Icons(CurrentIcon).Picture = LoadPicture(Viewer.File_FileList.FileName)
  347.  
  348.         ' If the Menu option is set, bring the Editor to the Foreground
  349.         ' when an Icon is loaded.
  350.         '
  351.         If Editor.Menu_ViewSelection(MID_FOCUS).Checked Then Editor.Show
  352.  
  353.         ' Simulate clicking the Icon in the StatusArea to take care of the
  354.         ' visual part of selection.
  355.         '
  356.         Select_New_Icon
  357.         Editor.Pic_ToolPalette.Refresh
  358.     Else
  359.         ' Do not discard the changes of the existing icon.
  360.         '
  361.         Editor.Pic_Icons(CurrentIcon).Cls
  362.         Magnify_Icon 0, 0, 31, 31
  363.     End If
  364.  
  365. End Sub
  366.  
  367. ' There are various situations when all or part of the current icon
  368. ' needs to be magnified and displayed in the editing area.  this
  369. ' routine is called to perform the magnification.  The Windows API
  370. ' routine, StretchBlt() is used to perform the magnification.
  371. '
  372. Sub Magnify_Icon(X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer)
  373. Dim DestX As Integer, DestY As Integer, DestWidth As Integer, DestHeight As Integer
  374. Dim srcWidth As Integer, srcHeight As Integer
  375.     
  376.     ' Ensure that X1 and Y1 refer to the upper left corner and X2 and Y2
  377.     ' refer to the lower right corner of the area to be magnified.
  378.     '
  379.     If X1 > X2 Then Swap_Values X1, X2
  380.     If Y1 > Y2 Then Swap_Values Y1, Y2
  381.  
  382.     ' The area to be magnified must not contain any pixels outside
  383.     ' of the Icon itself, so we must check for this situation and
  384.     ' adjust the values if neccessary.
  385.     '
  386.     If X1 < 0 Then X1 = 0
  387.     If X2 > 31 Then X2 = 31
  388.     If Y1 < 0 Then Y1 = 0
  389.     If Y2 > 31 Then Y2 = 31
  390.  
  391.     ' Calculate the width and height values of the source bitmap
  392.     '
  393.     srcWidth = X2 - X1 + 1
  394.     srcHeight = Y2 - Y1 + 1
  395.  
  396.     ' Calculate the destinations width, height and upper left corner
  397.     ' of the area to be magnified.
  398.     '
  399.     DestX = X1 * PixelSize
  400.     DestY = Y1 * PixelSize
  401.     DestWidth = srcWidth * PixelSize
  402.     DestHeight = srcHeight * PixelSize
  403.   
  404.     ' Magnify the icon.  We StretchBlt() from the image of the Icon in
  405.     ' the StatusArea to the Editing area.  Since we always maintain the
  406.     ' size of the Editing area a multiple of 32 (Size of an Icon), the
  407.     ' magnified icon will always be a perfect enlargement of the Icons
  408.     ' image.
  409.     '
  410.     If ImageSize = 1024 Then
  411.         '
  412.         StretchBlt Editor.Pic_Edit.hDC, DestX, DestY, DestWidth, DestHeight, Editor.Pic_Icons(CurrentIcon).hDC, X1, Y1, srcWidth, srcHeight, SRCCOPY
  413.         '
  414.         ' Redisplay the grid in the area that was magnified if the Grid option
  415.         ' is currently selected.
  416.         '
  417.         If Editor.Menu_ViewSelection(MID_GRID).Checked Then Display_Grid (Editor.Pic_Edit.hDC), X1, Y1, X2, Y2
  418.     Else
  419.         '
  420.         StretchBlt Editor.Pic_EditTemp.hDC, DestX, DestY, DestWidth, DestHeight, Editor.Pic_Icons(CurrentIcon).hDC, X1, Y1, srcWidth, srcHeight, SRCCOPY
  421.         '
  422.         ' Redisplay the grid in the area that was magnified if the Grid option
  423.         ' is currently selected.
  424.         '
  425.         If Editor.Menu_ViewSelection(MID_GRID).Checked Then Display_Grid (Editor.Pic_EditTemp.hDC), X1, Y1, X2, Y2
  426.         BitBlt Editor.Pic_Edit.hDC, DestX, DestY, DestWidth, DestHeight, Editor.Pic_EditTemp.hDC, DestX, DestY, SRCCOPY
  427.     End If
  428.  
  429.     ' Check if there is an active selection in the Editing area.  If so,
  430.     ' we must also redisplay the contents of the selection since the above
  431.     ' StretchBlt() operation may have entirely or partially covered up
  432.     ' the selection.
  433.     '
  434.     If MovingSelection Then
  435.         '
  436.         ' Calculate the width and height values of the source bitmap
  437.         ' containing the selection.  Always maintained in the global values
  438.         ' X1SelectFrom, Y1SelectFrom, X2SelectFrom, and Y2SelectFrom
  439.         '
  440.         srcWidth = X2SelectFrom - X1SelectFrom
  441.         srcHeight = Y2SelectFrom - Y1SelectFrom
  442.         
  443.         ' Calculate the destinations width and height of the area to be magnified.
  444.         '
  445.         DestWidth = srcWidth * PixelSize
  446.         DestHeight = srcHeight * PixelSize
  447.  
  448.         ' Determine type of Selection: Opaque, or Not Opaque.
  449.         '
  450.         If Opaque Then
  451.             '
  452.             ' Opaque selection: Magnify the selection bitmap including any Screen
  453.             ' or Inverse Screen attributes
  454.             '
  455.             StretchBlt Editor.Pic_Edit.hDC, X1Region, Y1Region, DestWidth, DestHeight, Editor.Pic_Work.hDC, X1SelectFrom, Y1SelectFrom, srcWidth, srcHeight, SRCCOPY
  456.         Else
  457.             ' None Opaque Selection: Magnify the selection bitmap but do not include
  458.             ' any Screen or Inverse Screen attributes.
  459.             '
  460.             StretchBlt Editor.Pic_Edit.hDC, X1Region, Y1Region, DestWidth, DestHeight, Editor.Pic_TempMask.hDC, X1SelectFrom, Y1SelectFrom, srcWidth, srcHeight, SRCAND
  461.             StretchBlt Editor.Pic_Edit.hDC, X1Region, Y1Region, DestWidth, DestHeight, Editor.Pic_TempImage.hDC, X1SelectFrom, Y1SelectFrom, srcWidth, srcHeight, SRCINVERT
  462.         End If
  463.     End If
  464.   
  465.     ' Redisplay the selection rectangle if currently making a selection
  466.     '
  467.     If Selecting Then Draw_Selection_Rectangle
  468.  
  469. End Sub
  470.  
  471. ' A Sub Main is used instead of a startup form to allow the user
  472. ' to startup either the Editor or Viewer as the main form.  The
  473. ' Editor is the Default main form, however starting IconWorks
  474. ' with a command line of "v" or "V" will start IconWorks with
  475. ' the Viewer as the main form.
  476. '
  477. Sub Main()
  478.   
  479.     ' Check video mode.  If less than EGA, terminate Iconworks
  480.     '
  481.     If Screen.Height < EGA_HEIGHT Then
  482.         MsgBox "IconWorks requires EGA or Better.", 16, "IconWorks"
  483.         End
  484.     Else
  485.         ' Since you cannot assign values like TAB, CR, and LF to string
  486.         ' constants, the values of TAB and CRLF which are used frequently
  487.         ' thoughout IconWorks when displaying messages, these values are
  488.         ' are assigned to the global string values of A_TAB and CRLF
  489.         '
  490.         A_TAB = Chr$(9)
  491.         CRLF = Chr$(13) + Chr$(10)
  492.  
  493.         If Not Help_File_In_Path() Then
  494.             Text = "ICONWRKS.HLP not found in your path." + CRLF + CRLF
  495.             Text = Text + "Windows searches your PATH environment variable for help files, "
  496.             Text = Text + "so you need to copy ICONWRKS.HLP to a directory included in your "
  497.             Text = Text + "PATH if you wish to obtain help while running IconWorks."
  498.             MsgBox Text, 48, "IconWorks help not available"
  499.         End If
  500.         
  501.         #If Win32 Then
  502.         With IID_IDispatch
  503.             .Data1 = &H20400
  504.             .Data4(0) = &HC0
  505.             .Data4(7) = &H46
  506.         End With
  507.         #End If
  508.         ' Determine which form to use as main form, Editor) or the Viewer
  509.         '
  510.         If (Command$ = "") Or (UCase$(Left$(Command$, 1)) <> "V") Then
  511.             '
  512.             ' Editor is main form
  513.             '
  514.             MainForm = ICONWORKS_EDITOR
  515.             Editor.Show
  516.         Else
  517.             ' Viewer is main form
  518.             '
  519.             MainForm = ICONWORKS_VIEWER
  520.             Viewer.Show
  521.         End If
  522.     End If
  523.  
  524. End Sub
  525.  
  526. ' Determines if an Icon has been modified since it was saved last, and
  527. ' prompts the user if so.
  528. '
  529. Function Ok_To_Discard_Changes()
  530.  
  531.     Text = ""
  532.     Ok_To_Discard_Changes = True
  533.  
  534.     ' Check if Icon has changed since it was last saved.
  535.     '
  536.     If ICONINFO(CurrentIcon).Changed Then
  537.         '
  538.         ' Inform user icon has been modifyied.
  539.         '
  540.         Text = Text + "Icon:" + A_TAB + "#" + Format$(CurrentIcon + 1) + CRLF
  541.         Text = Text + "Name:" + A_TAB + ICONINFO(CurrentIcon).FileName + CRLF
  542.         Text = Text + "Path:" + A_TAB + ICONINFO(CurrentIcon).FullPath + CRLF + CRLF
  543.         Text = Text + "Discard changes?"
  544.         Ok_To_Discard_Changes = MsgBox(Text, 36, "ICON HAS CHANGED") = MBYES
  545.     End If
  546.  
  547. End Function
  548.  
  549. ' Removes various menu items from the System menu of the specified Form.
  550. '
  551. Sub Remove_Items_From_Sysmenu(A_Form As Form)
  552. Dim hSysMenu
  553.  
  554.     ' Obtain the handle to the forms System menu
  555.     '
  556.     hSysMenu = GetSystemMenu(A_Form.hWnd, 0)
  557.   
  558.     ' Remove all but the MOVE and CLOSE options.  The menu items
  559.     ' must be removed starting with the last menu item.
  560.     '
  561.     RemoveMenu hSysMenu, 8, MF_BYPOSITION  'Switch to
  562.     RemoveMenu hSysMenu, 7, MF_BYPOSITION  'Separator
  563.     RemoveMenu hSysMenu, 5, MF_BYPOSITION 'Separator
  564.  
  565. End Sub
  566.  
  567. ' The rectanglular Region which is always defined by the global
  568. ' variables X1Region, Y1Region, X2Region, and Y2Region, is the
  569. ' basis for most of the tools in the toolpalette, and is frequently
  570. ' scaled from the scale of the Editing area down to the scale of
  571. ' the actual Icon, and in the reverse direction.  This routine
  572. ' performs the neccessary scaling, in either direction based on
  573. ' the value of *ToIcon*.
  574. '
  575. Sub Scale_Region(ToIcon As Boolean, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, CheckX1Y1 As Boolean)
  576.   
  577.     ' Determine which direction to scale
  578.     '
  579.     If ToIcon Then
  580.         '
  581.         ' Scale Global variables down to and Icon
  582.         '
  583.         X1 = X1Region \ PixelSize
  584.         Y1 = Y1Region \ PixelSize
  585.         X2 = X2Region \ PixelSize
  586.         Y2 = Y2Region \ PixelSize
  587.     
  588.         ' If requested, ensure X1 and Y1 refer to upper left corner
  589.         ' and X2 and Y2 refer to the lower right corner of the Region.
  590.         '
  591.         If CheckX1Y1 Then
  592.             If X1 > X2 Then Swap_Values X1, X2
  593.             If Y1 > Y2 Then Swap_Values Y1, Y2
  594.         End If
  595.     Else
  596.         ' Scale the values X1, Y1, X2, Y2 upto the Editing
  597.         ' area and assign to global variables
  598.         '
  599.         X1Region = X1 * PixelSize
  600.         Y1Region = Y1 * PixelSize
  601.         X2Region = X2 * PixelSize
  602.         Y2Region = Y2 * PixelSize
  603.     End If
  604.   
  605.  
  606. End Sub
  607.  
  608. ' When a new Icon from one of the 6 displayed within the StatusArea is selected
  609. ' or if a new icon is selected from the viewer to be edited, this routine is
  610. ' called to take care of the visual changes within the StatusArea.
  611. '
  612. Sub Select_New_Icon()
  613.     
  614.     Selecting = False
  615.     MovingSelection = False
  616.  
  617.     HighLight_Current_Icon
  618.  
  619.     Extract_Image_And_Mask Editor.Pic_Icons(CurrentIcon)
  620.       
  621.     ' Set the Undo Icon to the newly selected Icon.
  622.     '
  623.     Update_Icon Editor.Pic_Undo
  624.  
  625.     ' Display the icon in the editing area
  626.     '
  627.     Magnify_Icon 0, 0, 31, 31
  628.  
  629.     ' Display the Filename of the selected icon in the Editor's Titlebar
  630.     '
  631.     Editor.Caption = "IconWorks Editor: " + Format$(CurrentIcon + 1) + " - " + ICONINFO(CurrentIcon).FileName
  632.  
  633. End Sub
  634.  
  635. ' Since the Swap statement is not supported by Visual Basic, this
  636. ' routine is used to perform the task of swapping two integer values.
  637. '
  638. Sub Swap_Values(Param1 As Integer, Param2 As Integer)
  639. Dim Temp As Integer
  640.     Temp = Param1
  641.     Param1 = Param2
  642.     Param2 = Temp
  643.  
  644. End Sub
  645.  
  646. ' This routine is used by the SaveFileDlg and the Viewer to update the
  647. ' filespec displayed in the FileName TextBox whenever the forms Directory
  648. ' ListBox control is Single Clicked.  Since a Single click does not
  649. ' actually make a selection, this routine is called in response to a
  650. ' single click to display what would be the result if a double click
  651. ' is performed or if Enter is pressed.
  652. '
  653. Sub UpDate_FileSpec(A_Form As Form)
  654. Dim SelPath As String, CurPath As String, Slash As String, i As Integer
  655.  
  656.     CurPath = A_Form.Lbl_CurrentDirectory.Caption
  657.     SelPath = A_Form.Dir_DirectoryList.List(A_Form.Dir_DirectoryList.ListIndex)
  658.  
  659.     Select Case A_Form.Dir_DirectoryList.ListIndex
  660.         
  661.         Case Is >= 0
  662.             '
  663.             ' A subdirectory from the Current directory was selected
  664.             '
  665.             i = Right$(CurPath, 1) <> "\"
  666.             A_Form.Txt_FileName.Text = Right$(SelPath, Len(SelPath) - Len(CurPath) + i) + "\" + A_Form.File_FileList.Pattern
  667.         
  668.         Case Is = -1
  669.             '
  670.             ' The current directory was selected
  671.             '
  672.             A_Form.Txt_FileName.Text = A_Form.File_FileList.Pattern
  673.         
  674.         Case Is < -1
  675.             '
  676.             ' A parent directory of the Current directory was selected
  677.             '
  678.             SelPath = Right$(SelPath, Len(SelPath) - 2)
  679.             If Len(SelPath) > 1 Then Slash = "\"
  680.             A_Form.Txt_FileName.Text = SelPath + Slash + A_Form.File_FileList.Pattern
  681.     
  682.     End Select
  683.  
  684. End Sub
  685.  
  686. ' We do not actually modify the Icon directly, but modify the Mask and Image
  687. ' bitmaps that make up the Icon. So these bitmaps must be copied over the icons
  688. ' Mask and Image bitmaps after each edit to reflect the change in the actual
  689. ' icon displayed in the StatusArea.
  690. '
  691. Sub Update_Icon(Pic_Ctrl As Control)
  692. #If Win32 Then
  693. Dim hOldMonoBM
  694. Dim hDCWork
  695. Dim hBMOldWork
  696. Dim hBMWork
  697. Dim PDesc As PICTDESC
  698. Dim icoinfo As ICONINFO
  699. Dim IPic As IPicture
  700.     BitBlt hDCMono, 0, 0, 32, 32, Editor.Pic_Mask.hDC, 0, 0, SRCCOPY
  701.     SelectObject hDCMono, hBMOldMono
  702.     hDCWork = CreateCompatibleDC(0)
  703.     With Pic_Ctrl
  704.         hBMWork = CreateCompatibleBitmap(Editor.hDC, .Width, .Height)
  705.     End With
  706.     hBMOldWork = SelectObject(hDCWork, hBMWork)
  707.     BitBlt hDCWork, 0, 0, 32, 32, Editor.Pic_Image.hDC, 0, 0, SRCCOPY
  708.     SelectObject hDCWork, hBMOldWork
  709.     With icoinfo
  710.         .fIcon = 1
  711.         .xHotspot = 16
  712.         .yHotspot = 16
  713.         .hBMMask = hBMMono
  714.         .hBMColor = hBMWork
  715.     End With
  716.     With PDesc
  717.         .cbSizeofstruct = Len(PDesc)
  718.         .picType = PICTYPE_ICON
  719.         .Long1 = CreateIconIndirect(icoinfo)
  720.     End With
  721.     OleCreatePictureIndirect PDesc, IID_IDispatch, 1, IPic
  722.     Pic_Ctrl = IPic
  723.     hBMOldMono = SelectObject(hDCMono, hBMMono)
  724.     DeleteDC hDCWork
  725. #Else
  726. Dim Lpicon As Long
  727.     ' Convert the 4-Plane Mask Bitmap contained in the Picture Control to
  728.     ' a 1-Plane Bitmap.
  729.     '
  730.     BitBlt hDCMono, 0, 0, 32, 32, Editor.Pic_Mask.hDC, 0, 0, SRCCOPY
  731.  
  732.     ' Obtain a far Pointer to the actual Icons information and Bitmaps
  733.     ' and Lock this information so Windows will not move it.
  734.     '
  735.     Lpicon = GlobalLock(Pic_Ctrl.Picture)
  736.  
  737.     ' Replace the Icons Mask Bitmap with the new Mask Bitmap.
  738.     '
  739.     GetBitmapBits hBMMono, 128, Lpicon + 12
  740.  
  741.     ' Replace the Icons Image Bitmap with the new Image Bitmap.
  742.     '
  743.     GetBitmapBits Editor.Pic_Image.Image, ImageSize, Lpicon + 12 + 128
  744.  
  745.     ' Unlock the Icons memory so Windows is free to move it if neccessary
  746.     '
  747.     GlobalUnlock Pic_Ctrl.Picture
  748.  
  749.     ' Since VB is unaware of any modifications we make to the Icon using
  750.     ' any API routines, it does not know to redisplay the Icon, so we
  751.     ' must force it to display the new icon.
  752.     '
  753.     'Pic_Ctrl.Cls
  754.     UpdatePicture Pic_Ctrl.Picture
  755.     Pic_Ctrl.Cls
  756. #End If
  757.  
  758.     ' Set Changed Flag to TRUE since it has been modified.
  759.     '
  760.     If Pic_Ctrl.Tag <> Editor.Pic_Undo.Tag Then ICONINFO(CurrentIcon).Changed = True
  761.  
  762. End Sub
  763. #If Win16 Then
  764. Sub UpdatePicture(IPic As IPicture)
  765.     IPic.PictureChanged
  766. End Sub
  767. #End If
  768.  
  769. ' When either the Editors ColorPalette or the ColorPalette Forms
  770. ' Color Palette is clicked, this routine is called to set the selected
  771. ' color into the Mouse colors, and invoke the ColorPalette Form in
  772. ' the case of a Double Click event on the Editors Color Palette.
  773. '
  774. Sub Update_Mouse_Colors(Button, X As Single, Y As Single)
  775. Dim color As Long, SolidColor As Long, Index As Integer, i As Integer
  776.  
  777.     ' The ColorPalettes are a single picture control, so we must calculate
  778.     ' the color selected based on the coordinates of the mouse.
  779.     '
  780.     ColorIndex = Fix(X) + Fix(Y) * 16
  781.  
  782.     ' Obtain color from color array
  783.     '
  784.     color = Colors(ColorIndex)
  785.  
  786.     ' VB only supports 16 color mode, so we must obtain the nearest Solid
  787.     ' color to the selected color since the Screen and Inverse colors cannot
  788.     ' be set to dithered colors.
  789.     '
  790.     SolidColor = GetNearestColor(Editor.hDC, color)
  791.  
  792.     If DoubleClicked Then
  793.         '
  794.         ' The Editors ColorPalette was Double Clicked, so reset the Flag
  795.         ' and invoke the ColorPalette Form.
  796.         '
  797.         DoubleClicked = False
  798.         ColorPalette.Show
  799.  
  800.         ' The ColorPalette Forms initialization is done within the
  801.         ' GotFocus Event for its ColorPalette Picture control, so we
  802.         ' must give that Picture Control the focus.
  803.         '
  804.         ColorPalette.Pic_ColorPalette.SetFocus
  805.  
  806.     ElseIf Editor.Opt_Mouse(SCREEN_COLORS).Value And (color <> SolidColor) Then
  807.         '
  808.         ' An attempt to select a Dithered color into the Screen or Inverse
  809.         ' colors was made, so Prompt the user and do not allow the selection
  810.         '
  811.         MsgBox "Screen and Inverse colors can only be set to solid colors", 16, "Error"
  812.     Else
  813.         ' Obtain the the index of the corresponding mouse Color:
  814.         '   0 - Left Mouse Color
  815.         '   1 - Right Mouse Color
  816.         '   2 - Screen Color
  817.         '   3 - Inverse Screen Color
  818.         '
  819.         Index = Editor.Opt_Mouse(SCREEN_COLORS).Value * (-2) + Button - 1
  820.  
  821.         ' Replace the Mouse color with the new color
  822.         '
  823.         MouseColors(Index) = Colors(ColorIndex)
  824.  
  825.         ' Changing either the Screen Color or Inverse Screen Color also
  826.         ' changes the other so if either the Screen or Inverse color was
  827.         ' changed, we must change the other to its inverse.
  828.         '
  829.         If Index >= 2 Then
  830.             Editor.Pic_Icons(0).PSet (1, 1), MouseColors(Index)
  831.             MouseColors(Abs(Index - 5)) = Editor.Pic_Icons(0).Point(1, 1)
  832.             Editor.Pic_Icons(0).Cls
  833.         End If
  834.     
  835.         If Editor.Opt_Mouse(SCREEN_COLORS).Value Then
  836.             '
  837.             ' The Screen or Inverse Screen color was changed, so we must change
  838.             ' the BackColor of all 6 icons in the StatusArea and the Undo Icon to
  839.             ' the new Screen Color and then redisplay the selected Icon in the
  840.             ' Editing area.
  841.             '
  842.             HighLight_Current_Icon
  843.             For i = 0 To 5
  844.                 Editor.Pic_Icons(i).BackColor = MouseColors(2)
  845.             Next
  846.             Editor.Pic_Undo.BackColor = MouseColors(2)
  847.             Magnify_Icon 0, 0, 31, 31
  848.         End If
  849.  
  850.     End If
  851.  
  852.     ' Diplay the New Mouse colors at the Bottom of the StatusArea
  853.     '
  854.     Display_Mouse_Colors
  855.  
  856. End Sub
  857.  
  858. ' Selecting a new drive from the list of a Drive controls drop
  859. ' down list does not generate an error if the drive is not ready,
  860. ' so when a new drive is selected, we determine if it is ready
  861. ' or not.  This routine validates the selected drive and is use
  862. ' by both the SaveFileDlg's and Viewers's Drive control
  863. '
  864. Sub Validate_And_Change_Drives(A_Form As Form)
  865.     
  866.     On Error Resume Next
  867.     Err = False
  868.  
  869.     ' Invoking the Dir$() function with the selected drive will generate
  870.     ' an error if the drive is not ready.  We don't care about the return
  871.     ' value, we just care if an error is generated or not.
  872.     '
  873.     Dir$ Left$(A_Form.Drv_DriveList.Drive, 2)
  874.  
  875.     If Err Then
  876.         '
  877.         ' The drive was not ready, so prompt the user
  878.         '
  879.         Beep
  880.         MsgBox Error$(Err), 16, "IconWorks - ERROR: " + Format$(Err)
  881.  
  882.         ' Reset the Drive Control back to its previously selected drive
  883.         '
  884.         A_Form.Drv_DriveList.Drive = Left$(A_Form.Dir_DirectoryList.Path, 2)
  885.     Else
  886.         ' The drive is ready, so change to that drive
  887.         '
  888.         ChDrive A_Form.Drv_DriveList.Drive
  889.         A_Form.Dir_DirectoryList.Path = CurDir$
  890.     End If
  891.   
  892.     On Error GoTo 0
  893.  
  894. End Sub
  895.  
  896. ' When a filespec is entered into either the Viewer's Filename
  897. ' TextBox or the SaveFileDlg's Filename TextBox, this routine is
  898. ' called to validate the FileSpec.  The name and path, if one is
  899. ' given, is validated.  If a valid FileSpec to an actual file is
  900. ' entered and the file does not exist, the return value depends
  901. ' on which Form called this routine, since a if called from the
  902. ' SaveFileDlg a "File Not Found" error is generated but that is
  903. ' OK since a file does not have to exist to write to it.  However,
  904. ' if called from the Viewer, the same error will be generated but
  905. ' in this case the file must exists since the Viewer is wants to
  906. ' open the file for editing.
  907. '
  908. Function Validate_FileSpec(AForm As Form, MustExist)
  909. Dim Temp As String, PeriodPos As Integer, LeftOfPeriod$
  910.  
  911.     ' Enable error trapping
  912.     '
  913.     On Error GoTo ErrorInSpec
  914.  
  915.     Validate_FileSpec = False
  916.  
  917.     ' Check for valid DOS Path and Filenames.
  918.     '
  919.     Temp = Dir$(AForm.Txt_FileName.Text)
  920.  
  921.     ' The following statement does alot.  It the FileSpec contains
  922.     ' a Path, the FileSpec will be parsed and the Path will be assign
  923.     ' to the File ListBox's Path property.  If the FileSpec contains
  924.     ' Wild card characters, it will be assign to the File ListBox's
  925.     ' pattern property.  If the FileSpec contains a valid file name
  926.     ' and the file exists, a Double Click event will automatically be
  927.     ' generated for the File ListBox.  If the File does not exist,
  928.     ' a "File Not Found" error will be generated which we trap.
  929.     '
  930.     AForm.File_FileList.FileName = AForm.Txt_FileName.Text
  931.   
  932. Exit_The_Function:
  933.  
  934.     ' Turn off error trapping and exit the function
  935.     '
  936.     On Error GoTo 0
  937.     Exit Function
  938.  
  939. ErrorInSpec:
  940.     If (Err <> FILE_NOT_FOUND) Or ((Err = FILE_NOT_FOUND) And MustExist) Then
  941.         '
  942.         ' An error other than "File Not Found" occured, or the error
  943.         ' "File Not Found" occured and this Function was invoked from
  944.         ' the Viewer which requires the file to exist.
  945.         '
  946.         Beep
  947.         MsgBox Error$(Err), 16, "IconWorks - ERROR: " + Format$(Err)
  948.     Else
  949.         ' The FileSpec entered contain no errors other than maybe
  950.         ' "File Not Found".
  951.         '
  952.         If Err = FILE_NOT_FOUND Then
  953.             ' A Valid filename was entered in the SaveFileDlg which did not exist
  954.             ' so the File Control did not parse the FileSpec for us.  Since the
  955.             ' FileSpec could contain a path specification, force File control
  956.             ' to parse the Filename string for us by changing last character to
  957.             ' an asterisk "*" and assign the modified FileSpec to the File Controls
  958.             ' FileName property.  The asterisk "*" makes the Filename appear as a
  959.             ' FileSpec rather than a Filename to the File ListBox and it will parse
  960.             ' it for us whether there are any matching files or not.  After it has
  961.             ' been parsed, we change the "*" back to its previous value.
  962.             '
  963.             Temp = Right$(AForm.Txt_FileName.Text, 1)
  964.             AForm.File_FileList.FileName = Left$(AForm.Txt_FileName.Text, Len(AForm.Txt_FileName.Text) - 1) + "*"
  965.             AForm.Txt_FileName.Text = Left$(AForm.File_FileList.Pattern, Len(AForm.File_FileList.Pattern) - 1) + Temp
  966.             
  967.             ' This checks to see that that file name that has been parsed
  968.             ' is a valid DOS file name
  969.  
  970.              PeriodPos = InStr(1, AForm.Txt_FileName.Text, ".")
  971.              If PeriodPos <> 0 Then
  972.                 LeftOfPeriod$ = Left$(AForm.Txt_FileName.Text, PeriodPos - 1)
  973.              Else
  974.                LeftOfPeriod$ = AForm.Txt_FileName.Text
  975.              End If
  976.              If Len(AForm.Txt_FileName.Text) > 8 Then
  977.                      Resume Exit_The_Function
  978.             End If
  979.             Else
  980.         End If
  981.         Validate_FileSpec = True
  982.     End If
  983.     Resume Exit_The_Function
  984.  
  985. End Function
  986.  
  987. ' Saves the current icon to disk, and updates the Icon menu and
  988. ' Editors title bar with the new Icons filename.
  989. '
  990. Sub Write_Icon_To_File(FullPath As String, FileName As String)
  991.   
  992.     ' Save new Filename and Path information for the Icon
  993.     '
  994.     ICONINFO(CurrentIcon).FileName = FileName
  995.     ICONINFO(CurrentIcon).FullPath = FullPath
  996.     ICONINFO(CurrentIcon).Changed = False
  997.  
  998.     ' Display the Icons Filename and Path in the Editors Icon menu
  999.     '
  1000.     Editor.Menu_IconsSelection(CurrentIcon).Caption = "&" + Format$(CurrentIcon + 1) + " - [" + FullPath + "]" + A_TAB + FileName
  1001.  
  1002.     ' Display the Icons Filename in the Editors TitleBar
  1003.     '
  1004.     Editor.Caption = "IconWorks Editor: " + Format$(CurrentIcon + 1) + " - " + FileName
  1005.  
  1006.     ' Save the Icon to the specified File in the Specified Directory
  1007.     '
  1008.     If Right$(FullPath, 1) <> "\" Then FullPath = FullPath + "\"
  1009.     SavePicture Editor.Pic_Icons(CurrentIcon).Picture, FullPath + FileName
  1010.  
  1011. End Sub
  1012.  
  1013.