diff options
-rw-r--r-- | SpriteEd/Main.storyboard | 93 | ||||
-rw-r--r-- | SpriteEd/NSSpriteEdit.cs | 193 | ||||
-rw-r--r-- | SpriteEd/Util.cs | 24 | ||||
-rw-r--r-- | SpriteEd/ViewController.cs | 47 | ||||
-rw-r--r-- | SpriteEd/ViewController.designer.cs | 48 |
5 files changed, 379 insertions, 26 deletions
diff --git a/SpriteEd/Main.storyboard b/SpriteEd/Main.storyboard index b6d561e..bf0d76a 100644 --- a/SpriteEd/Main.storyboard +++ b/SpriteEd/Main.storyboard @@ -685,11 +685,12 @@ <objects> <windowController id="B8D-0N-5wS" sceneMemberID="viewController"> <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA"> - <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="196" y="240" width="480" height="270"/> + <rect key="contentRect" x="196" y="240" width="800" height="600"/> <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/> - <value key="minSize" type="size" width="480" height="270"/> + <value key="minSize" type="size" width="800" height="600"/> + <value key="maxSize" type="size" width="800" height="600"/> <connections> <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/> </connections> @@ -707,11 +708,11 @@ <objects> <viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController"> <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl"> - <rect key="frame" x="0.0" y="0.0" width="480" height="270"/> + <rect key="frame" x="0.0" y="0.0" width="800" height="600"/> <autoresizingMask key="autoresizingMask"/> <subviews> <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vru-p3-CZW"> - <rect key="frame" x="20" y="229" width="41" height="21"/> + <rect key="frame" x="20" y="559" width="41" height="21"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" allowsUndo="NO" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="8w4-fI-HAj"> <font key="font" usesAppearanceFont="YES"/> @@ -720,41 +721,107 @@ </textFieldCell> </textField> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OOh-QE-F3j"> - <rect key="frame" x="88" y="231" width="374" height="16"/> + <rect key="frame" x="88" y="561" width="315" height="16"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="kKb-aN-vLt"> + <textFieldCell key="cell" lineBreakMode="clipping" title="Code description" id="kKb-aN-vLt"> <font key="font" metaFont="system"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> </textField> - <customView ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lP9-z2-hEq" customClass="NSSpriteEdit"> - <rect key="frame" x="20" y="20" width="440" height="204"/> + <customView translatesAutoresizingMaskIntoConstraints="NO" id="lP9-z2-hEq" customClass="NSSpriteEdit"> + <rect key="frame" x="20" y="20" width="760" height="530"/> </customView> <stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6aS-x3-0ku"> - <rect key="frame" x="66" y="225" width="19" height="28"/> + <rect key="frame" x="66" y="555" width="19" height="28"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <stepperCell key="cell" continuous="YES" alignment="left" maxValue="255" id="MdJ-Rv-znP"/> <connections> - <action selector="OnStepper:" target="XfG-lQ-9wD" id="S2o-Tu-VQ1"/> + <action selector="OnSpriteStepper:" target="XfG-lQ-9wD" id="fag-ib-taE"/> </connections> </stepper> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iXZ-D0-tCL"> + <rect key="frame" x="707" y="559" width="41" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="uD4-8J-1jJ"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FGJ-Vk-aSZ"> + <rect key="frame" x="753" y="555" width="19" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <stepperCell key="cell" continuous="YES" alignment="left" maxValue="100" id="6Ed-My-HbU"/> + <connections> + <action selector="OnColourStepper:" target="XfG-lQ-9wD" id="oY0-Qe-9MW"/> + </connections> + </stepper> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7k9-2M-yvh"> + <rect key="frame" x="656" y="561" width="45" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Colour" id="ai2-Hw-vQI"> + <font key="font" metaFont="system"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="n1P-N7-3af"> + <rect key="frame" x="412" y="562" width="92" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Drawing Mode" id="uxJ-en-Zkt"> + <font key="font" metaFont="system"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hCT-dA-Ray"> + <rect key="frame" x="508" y="556" width="145" height="25"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <popUpButtonCell key="cell" type="push" title="Point" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="4oB-U5-ere" id="yQ6-sF-FRH"> + <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + <menu key="menu" id="ck7-KM-LOl"> + <items> + <menuItem title="Point" state="on" id="4oB-U5-ere"/> + <menuItem title="Line" tag="1" id="mxD-u9-ERi"/> + <menuItem title="Rectangle" tag="2" id="hYO-Md-Gun"/> + <menuItem title="Filled Rectangle" tag="3" id="R3s-9w-AFc"> + <modifierMask key="keyEquivalentModifierMask"/> + </menuItem> + <menuItem title="Circle" tag="4" id="z7a-XR-mup"> + <modifierMask key="keyEquivalentModifierMask"/> + </menuItem> + <menuItem title="Filled Circle" tag="5" id="7VK-vs-1sB"> + <modifierMask key="keyEquivalentModifierMask"/> + </menuItem> + </items> + </menu> + </popUpButtonCell> + <connections> + <action selector="OnDrawingMode:" target="XfG-lQ-9wD" id="OSG-SN-lRu"/> + </connections> + </popUpButton> </subviews> <constraints> <constraint firstAttribute="trailing" secondItem="lP9-z2-hEq" secondAttribute="trailing" constant="20" id="CVb-3j-Tmy"/> + <constraint firstItem="lP9-z2-hEq" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="50" id="SOh-KZ-B6U"/> <constraint firstItem="lP9-z2-hEq" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="20" id="Tf2-9p-pzx"/> <constraint firstAttribute="bottom" secondItem="lP9-z2-hEq" secondAttribute="bottom" constant="20" id="sut-hb-VF4"/> </constraints> </view> <connections> + <outlet property="m_ColourLabel" destination="7k9-2M-yvh" id="8AR-Od-bNf"/> + <outlet property="m_ColourNumber" destination="iXZ-D0-tCL" id="WmO-5c-JnK"/> + <outlet property="m_ColourStepper" destination="FGJ-Vk-aSZ" id="tD6-1U-5C7"/> <outlet property="m_SpriteEdit" destination="lP9-z2-hEq" id="mYk-Ot-hkR"/> <outlet property="m_SpriteNumber" destination="Vru-p3-CZW" id="0e9-Xv-W5Q"/> - <outlet property="m_Stepper" destination="6aS-x3-0ku" id="RFh-7I-DGa"/> + <outlet property="m_SpriteStepper" destination="6aS-x3-0ku" id="Kfe-FD-nLY"/> </connections> </viewController> <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="75" y="655"/> + <point key="canvasLocation" x="436" y="1037"/> </scene> </scenes> </document> diff --git a/SpriteEd/NSSpriteEdit.cs b/SpriteEd/NSSpriteEdit.cs index 4f6d0c5..605e69f 100644 --- a/SpriteEd/NSSpriteEdit.cs +++ b/SpriteEd/NSSpriteEdit.cs @@ -30,15 +30,89 @@ namespace SpriteEd public class NSSpriteEdit : NSControl { /// <summary> + /// The drawing mode for the sprite control. + /// </summary> + public enum DrawingMode + { + /// <summary> + /// Draw single points. + /// </summary> + Point, + + /// <summary> + /// Draw lines. + /// </summary> + Line, + + /// <summary> + /// Draw a rectangle. + /// </summary> + Rect, + + /// <summary> + /// Draw a filled rectangle. + /// </summary> + FilledRect, + + /// <summary> + /// Draw a circle. + /// </summary> + Circle, + + /// <summary> + /// Draw a filled circle. + /// </summary> + FilledCircle + } + + private Sprite m_sprite; + private int m_cx; + private int m_cy; + + /// <summary> /// The sprite being edited. /// </summary> - public Sprite Sprite {get;set;} + public Sprite Sprite + { + set + { + m_sprite = value; + NeedsDisplay = true; + } + } + + /// <summary> + /// Set the drawing mode. + /// </summary> + public DrawingMode Mode {private get; set;} + + /// <summary> + /// The sprite palette. + /// </summary> + public Palette Palette {private get; set;} + + /// <summary> + /// The palette colour to use for drawing. + /// </summary> + public uint Colour {private get; set;} + + /// <summary> + /// Whether the sprite has double width pixels. + /// </summary> + public bool DoubleWidth {get; set;} + + /// <summary> + /// Whether the sprite has double height pixels. + /// </summary> + public bool DoubleHeight {get; set;} /// <summary> /// Default constructor /// </summary> public NSSpriteEdit() { + m_cx = -1; + m_cy = -1; Init(); } @@ -67,6 +141,99 @@ namespace SpriteEd LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay; } + private uint BlockSizeX + { + get + { + uint bx = m_sprite.Width * (DoubleWidth ? 2u : 1u); + uint s = (uint)Math.Min(Frame.Width, Frame.Height); + + if (!(DoubleWidth ^ DoubleHeight)) + { + return s/bx * (DoubleWidth ? 2u : 1u); + } + else if (DoubleWidth) + { + return s/bx * 2u; + } + else + { + return s/bx / 2u; + } + } + } + + private uint BlockSizeY + { + get + { + uint by = m_sprite.Height * (DoubleHeight ? 2u : 1u); + uint s = (uint)Math.Min(Frame.Width, Frame.Height); + + if (!(DoubleWidth ^ DoubleHeight)) + { + return s/by * (DoubleHeight ? 2u : 1u); + } + else if (DoubleWidth) + { + return s/by / 2u; + } + else + { + return s/by * 2u; + } + } + } + + private void DrawGrid(CGContext context, uint x, uint y) + { + uint bsx = BlockSizeX; + uint bsy = BlockSizeY; + Colour white = new Colour(255, 255, 255); + + x *= bsx; + y = (uint)Frame.Height - y * bsy; + + DrawLine(context, x, y, x + bsx, y, white); + DrawLine(context, x + bsx, y, x + bsx, y - bsy, white); + DrawLine(context, x + bsx, y - bsy, x, y - bsy, white); + DrawLine(context, x, y - bsy, x, y, white); + } + + private void DrawCell(CGContext context, uint x, uint y, Colour colour) + { + uint bsx = BlockSizeX; + uint bsy = BlockSizeY; + + x *= bsx; + y = (uint)Frame.Height - (y + 1) * bsy; + + CGRect rect = new CGRect(x + 1, y + 1, bsx - 1, bsy - 1); + + DrawFilledRect(context, rect, colour); + } + + private void DrawFilledRect(CGContext context, CGRect rect, Colour colour) + { + using (CGColor cgcol = Util.ColourCG(colour)) + { + context.SetFillColor(cgcol); + context.FillRect(rect); + } + } + + private void DrawLine(CGContext context, uint x1, uint y1, uint x2, uint y2, Colour colour) + { + using (CGColor cgcol = Util.ColourCG(colour)) + { + context.SetLineWidth(1.0f); + context.SetStrokeColor(cgcol); + context.MoveTo(x1, y1); + context.AddLineToPoint(x2, y2); + context.DrawPath(CGPathDrawingMode.Stroke); + } + } + /// <summary> /// Redraw the control. /// </summary> @@ -76,6 +243,30 @@ namespace SpriteEd base.DrawRect (dirtyRect); // TODO: Draw control + if (m_sprite != null) + { + CGContext context = NSGraphicsContext.CurrentContext.GraphicsPort; + + Colour black = new Colour(); + + DrawFilledRect(context, dirtyRect, black); + + context.ClipToRect(dirtyRect); + + for(uint x = 0; x < m_sprite.Width; x++) + { + for (uint y = 0; y < m_sprite.Height; y++) + { + DrawGrid(context, x, y); + DrawCell(context, x, y, Palette[m_sprite[x,y]]); + } + } + + if (m_cx != -1 && m_cx != -1) + { + DrawCell(context, (uint)m_cx, (uint)m_cy, Palette[Colour]); + } + } } } } diff --git a/SpriteEd/Util.cs b/SpriteEd/Util.cs index cca9c47..dff6e3e 100644 --- a/SpriteEd/Util.cs +++ b/SpriteEd/Util.cs @@ -17,6 +17,7 @@ using System; using System.IO; using AppKit; +using CoreGraphics; namespace SpriteEd { @@ -94,5 +95,28 @@ namespace SpriteEd alert.RunModal(); } + + /// <summary> + /// Convert a sprite Colour into an NSColor + /// </summary> + /// <param name="c">The colour.</param> + /// <returns></returns> + public static NSColor ColourNS(Colour c) + { + return NSColor.FromDeviceRgb(c.Red, c.Green, c.Blue); + } + + /// <summary> + /// Convert a Colour into a CGColor. + /// </summary> + /// <param name="c">The colour.</param> + /// <returns></returns> + public static CGColor ColourCG(Colour c) + { + return CGColor.CreateSrgb((float)c.Red / 255.0f, + (float)c.Green / 255.0f, + (float)c.Blue / 255.0f, + 1.0f); + } } } diff --git a/SpriteEd/ViewController.cs b/SpriteEd/ViewController.cs index 82732a3..8b4aca1 100644 --- a/SpriteEd/ViewController.cs +++ b/SpriteEd/ViewController.cs @@ -34,14 +34,28 @@ namespace SpriteEd { base.ViewDidLoad(); - m_SpriteNumber.IntValue = 0; - m_Stepper.IntValue = 0; + m_SpriteStepper.IntValue = 0; m_Palette = new Palette(2); m_Palette[0] = new Colour(0, 0, 0); m_Palette[1] = new Colour(255, 255, 255); + m_ColourStepper.IntValue = 1; + + m_ColourStepper.MaxValue = m_Palette.Size - 1; + m_SpriteSet = new SpriteSet(8, 8, m_Palette, false, false); + + m_SpriteEdit.Palette = m_Palette; + m_SpriteEdit.DoubleWidth = m_SpriteSet.DoubleWidth; + m_SpriteEdit.DoubleHeight = m_SpriteSet.DoubleHeight; + m_SpriteEdit.Sprite = m_SpriteSet[(byte)m_SpriteNumber.IntValue]; + m_SpriteEdit.Mode = NSSpriteEdit.DrawingMode.Point; + + m_SpriteSet[0][0,0] = 1; + + OnColourStepper(m_ColourStepper); + OnSpriteStepper(m_SpriteStepper); } public override NSObject RepresentedObject @@ -57,13 +71,40 @@ namespace SpriteEd } } - partial void OnStepper(NSObject sender) + partial void OnSpriteStepper(NSObject sender) { NSStepper stepper = sender as NSStepper; if (stepper != null) { m_SpriteNumber.IntValue = stepper.IntValue; + m_SpriteEdit.Sprite = m_SpriteSet[(byte)stepper.IntValue]; + } + } + + partial void OnColourStepper(NSObject sender) + { + NSStepper stepper = sender as NSStepper; + + if (stepper != null) + { + m_ColourNumber.IntValue = stepper.IntValue; + m_SpriteEdit.Colour = (uint)stepper.IntValue; + + using (NSColor c = Util.ColourNS(m_Palette[(uint)stepper.IntValue])) + { + m_ColourLabel.TextColor = c; + } + } + } + + partial void OnDrawingMode(NSObject sender) + { + NSPopUpButton button = sender as NSPopUpButton; + + if (button != null) + { + m_SpriteEdit.Mode = (NSSpriteEdit.DrawingMode)(int)button.SelectedTag; } } } diff --git a/SpriteEd/ViewController.designer.cs b/SpriteEd/ViewController.designer.cs index 9ea3fc9..2de4b18 100644 --- a/SpriteEd/ViewController.designer.cs +++ b/SpriteEd/ViewController.designer.cs @@ -13,33 +13,63 @@ namespace SpriteEd partial class ViewController { [Outlet] + AppKit.NSTextField m_ColourLabel { get; set; } + + [Outlet] + AppKit.NSTextField m_ColourNumber { get; set; } + + [Outlet] + AppKit.NSStepper m_ColourStepper { get; set; } + + [Outlet] SpriteEd.NSSpriteEdit m_SpriteEdit { get; set; } [Outlet] AppKit.NSTextField m_SpriteNumber { get; set; } [Outlet] - AppKit.NSStepper m_Stepper { get; set; } + AppKit.NSStepper m_SpriteStepper { get; set; } + + [Action ("OnColourStepper:")] + partial void OnColourStepper (Foundation.NSObject sender); + + [Action ("OnDrawingMode:")] + partial void OnDrawingMode (Foundation.NSObject sender); - [Action ("OnStepper:")] - partial void OnStepper (Foundation.NSObject sender); + [Action ("OnSpriteStepper:")] + partial void OnSpriteStepper (Foundation.NSObject sender); void ReleaseDesignerOutlets () { - if (m_SpriteNumber != null) { - m_SpriteNumber.Dispose (); - m_SpriteNumber = null; + if (m_ColourLabel != null) { + m_ColourLabel.Dispose (); + m_ColourLabel = null; + } + + if (m_ColourNumber != null) { + m_ColourNumber.Dispose (); + m_ColourNumber = null; } - if (m_Stepper != null) { - m_Stepper.Dispose (); - m_Stepper = null; + if (m_ColourStepper != null) { + m_ColourStepper.Dispose (); + m_ColourStepper = null; } if (m_SpriteEdit != null) { m_SpriteEdit.Dispose (); m_SpriteEdit = null; } + + if (m_SpriteNumber != null) { + m_SpriteNumber.Dispose (); + m_SpriteNumber = null; + } + + if (m_SpriteStepper != null) { + m_SpriteStepper.Dispose (); + m_SpriteStepper = null; + } } } } |