gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Questions to NSButtonCell


From: Christopher Armstrong
Subject: Re: Questions to NSButtonCell
Date: Tue, 23 Jan 2007 09:14:41 +1100
User-agent: Thunderbird 1.5.0.9 (Windows/20061207)

Hi

Quite coincidentally, I've been playing around with this stuff myself in an attempt to develop further the theming API. I've been having trouble trying to sort out some of these problems as well. I was going to develop further what I was working on for submitting it, but I may as well share it now to avoid duplication. Find attached a patch against the gnustep-gui theming branch in SVN (please note it contains some extra API's I've been prototyping but haven't used yet, plus some documentation for NSScroller that I need to separate out and submit as a different patch).

address@hidden wrote:
While I working on NSButtonCell I stumbled over a few questions that I
am not able to solve myself. Perhaps one of you knows some of the answers.

2. Cell Frame
All my previous test on MacOSX suggest, that the cell frame being passed
into drawInteriorWithFrame:inView: is exactly the same that did get
passed into drawWithFrame:inView:. But in the current GNUstep
implementation this frame gets reduced by the size of the bezel border.
This solution is a lot more elegant, but it will break porting between
Cocoa and GNUstep, if there is indeed a difference. I think what we need
to do is correct drawingRectForBounds: to ask the theme for the size of
the border.
Reading the Cocoa documentation and some old OpenStep documentation, -drawInteriorWithFrame:inView: is supposed to receive the same frame as -drawWithFrame:inView:, but it could be slightly reduced for unspecified reasons. It is ambiguous why it should be reduced, but I don't think it would be as a result of the border or bezel. My attached patch calls a method in the theme to determine this information.
3. border and bezel
Now NSCell has two different concepts for its border. It is either a
simple line, in which case it is called border, or a more complex thing,
then it is called bezel. For NSButtonCell these two seem to be merged.
Our code only checks the border flag, but it will draw a bezel.
I think that our code is correct, but we should get it better in sync
with the cell code.
I noticed this also. I couldn't decipher the Cocoa docs to make exactly clear what a "border" is, but I think its supposed to be a black line. The bezel stuff is the fancier button types I think. The border flag is possibly being used incorrectly in this case.

Cheers
Chris
Index: Source/GNUmakefile
===================================================================
--- Source/GNUmakefile  (revision 24388)
+++ Source/GNUmakefile  (working copy)
@@ -182,6 +182,7 @@
 externs.m \
 linking.m \
 GSTheme.m \
+GSTheme_menu.m \
 GSDragView.m \
 GSFontInfo.m \
 GSTable.m \
Index: Source/GSTheme.m
===================================================================
--- Source/GSTheme.m    (revision 24388)
+++ Source/GSTheme.m    (working copy)
@@ -767,8 +767,122 @@
 
 @end
 
-
address@hidden GSTheme (ButtonDrawing)
 
+- (void)       button: (NSButtonCell*)cell
+        drawWithFrame: (NSRect)frame 
+               inView: (NSControl*)controlView
+                style: (int)style 
+                state: (GSThemeControlState)state
+{
+  GSDrawTiles  *tiles = nil;
+  NSColor      *color = nil;
+  NSRect       interiorFrame;
+
+  if (state == GSThemeNormalState)
+    {
+      tiles = [self tilesNamed: @"NSButtonNormal" cache: YES];
+      color = [NSColor controlBackgroundColor];
+    }
+  else if (state == GSThemeHighlightedState)
+    {
+      tiles = [self tilesNamed: @"NSButtonHighlighted" cache: YES];
+      color = [NSColor selectedControlColor];
+    }
+  else if (state == GSThemeSelectedState)
+    {
+      tiles = [self tilesNamed: @"NSButtonPushed" cache: YES];
+      color = [NSColor selectedControlColor];
+    }
+
+  if (tiles == nil)
+    {
+      interiorFrame = [cell drawingRectForBounds: frame];
+      [color set];
+      NSRectFill(frame);
+
+      if (state == GSThemeNormalState)
+       {
+         [self drawButton: frame withClip: NSZeroRect];
+       }
+      else if (state == GSThemeHighlightedState)
+       {
+         [self drawGrayBezel: frame withClip: NSZeroRect];
+       }
+      else if (state == GSThemeSelectedState)
+       {
+         [self drawGrayBezel: frame withClip: NSZeroRect];
+         interiorFrame
+           = NSOffsetRect(interiorFrame, 1.0, 
+                [controlView isFlipped] ? 1.0 : -1.0);
+       }
+    }
+  else
+    {
+      /* Use tiles to draw button border with central part filled with color
+       */
+      interiorFrame = [self fillRect: frame
+                          withTiles: tiles
+                         background: color
+                          fillStyle: GSThemeFillStyleNone];
+    }
+
+  //return interiorFrame;
+}
+
+- (NSSize) buttonBorderSize:(NSButtonCell*)cell
+{
+  // FIXME: Make this method find out the size of the tiles.
+  BOOL bordered, bezeled;
+  NSCellImagePosition imagePosition;
+  NSSize borderSize;
+
+  bordered = [cell isBordered];
+  bezeled = [cell isBezeled];
+  imagePosition = [cell imagePosition];
+  if (bordered)
+    borderSize = NSMakeSize(3.0, 3.0);
+  else
+    borderSize = NSZeroSize;
+  
+  if ((bordered && (imagePosition != NSImageOnly)) || bezeled)
+  {
+    borderSize.width += 6.0;
+    borderSize.height += 6.0;
+  }
+  return borderSize;
+}
+
+- (NSRect) button:(NSButtonCell*)cell
+    drawingRectForBounds:(NSRect)theRect
+{
+  if ([cell isBordered])
+    {
+      /* 
+       * Special case:  Buttons have only three different paths for border.
+       * One white path at the top left corner, one black path at the
+       * bottom right and another in dark gray at the inner bottom right.
+       */ 
+      float yDelta = [[cell controlView] isFlipped] ? 1. : 2.;
+      return NSMakeRect (theRect.origin.x + 1.,
+                        theRect.origin.y + yDelta,
+                        theRect.size.width - 3.,
+                        theRect.size.height - 3.);
+    }
+  else
+    {
+      return theRect;
+    }
+}
+
+- (void) button:(NSButtonCell*)cell drawFocusWithRect:(NSRect)cellFrame
+   inView:(NSControl*)controlView
+{
+  [self drawFocusFrame:[cell drawingRectForBounds:cellFrame] view:controlView];
+}
address@hidden
+
+
 @implementation        GSTheme (MidLevelDrawing)
 
 - (NSRect) drawButton: (NSRect)border withClip: (NSRect)clip
Index: Source/NSButtonCell.m
===================================================================
--- Source/NSButtonCell.m       (revision 24388)
+++ Source/NSButtonCell.m       (working copy)
@@ -890,10 +890,12 @@
   if ((_cell.is_bordered)
     && (!_shows_border_only_while_mouse_inside || _mouse_inside))
     {
-      cellFrame = [[GSTheme theme]
-         drawButton: cellFrame in: self view: controlView
-              style: _bezel_style
-              state: buttonState];
+      [[GSTheme theme]
+         button: self 
+  drawWithFrame: cellFrame 
+         inView: controlView
+          style: _bezel_style
+          state: buttonState];
     }
 
   [self drawInteriorWithFrame: cellFrame inView: controlView];
@@ -902,7 +904,10 @@
   if (_cell.shows_first_responder
     && [[controlView window] firstResponder] == controlView)
     {
-      [[GSTheme theme] drawFocusFrame: cellFrame view: controlView];
+      //[[GSTheme theme] drawFocusFrame:[self drawingRectForBounds:cellFrame]  
+      //  view: controlView];
+      [[GSTheme theme] button:self drawFocusWithRect:cellFrame
+        inView:controlView];
     }
 }
 
@@ -1333,6 +1338,8 @@
     }
   
   // Get border size
+  borderSize = [[GSTheme theme] buttonBorderSize:self];
+  /*
   if (_cell.is_bordered)
     // Buttons only have three paths for border (NeXT looks)
     borderSize = NSMakeSize (3.0, 3.0);
@@ -1345,7 +1352,7 @@
       borderSize.width += 6;
       borderSize.height += 6;
     }
-
+  */
   // Add border size
   s.width += borderSize.width;
   s.height += borderSize.height;
@@ -1355,14 +1362,15 @@
 
 - (NSRect) drawingRectForBounds: (NSRect)theRect
 {
+  return [[GSTheme theme] button:self drawingRectForBounds:theRect];
   // FIXME
-  if (_cell.is_bordered)
+  /*if (_cell.is_bordered)
     {
-      /*
+      
        * Special case:  Buttons have only three different paths for border.
        * One white path at the top left corner, one black path at the
        * bottom right and another in dark gray at the inner bottom right.
-       */
+       
       float yDelta = [_control_view isFlipped] ? 1. : 2.;
       return NSMakeRect (theRect.origin.x + 1.,
                         theRect.origin.y + yDelta,
@@ -1373,6 +1381,7 @@
     {
       return theRect;
     }
+  */
 }
 
 - (void) setSound: (NSSound *)aSound
Index: Source/NSScroller.m
===================================================================
--- Source/NSScroller.m (revision 24388)
+++ Source/NSScroller.m (working copy)
@@ -42,8 +42,11 @@
 #include "AppKit/NSColor.h"
 #include "AppKit/NSGraphics.h"
 
-/**<p>TODO Description</p>
- */
+/**
+  * <p>The NSScroller class represents a scrollbar control. They are usually
+  * shown automatically in other controls that need a scrolling implementation
+  * such as tableviews.</p>
+  */
 @implementation NSScroller
 
 /*
@@ -101,7 +104,7 @@
 /** <p>Returns the position of the NSScroller's arrows used for scrolling 
     By default the arrow position is set to <ref type="type" 
     id="NSScrollArrowPosition">NSScrollerArrowsMinEnd</ref> if the 
-    scrolletr is a horizontal scroller and <ref type="type" 
+    scroller is a horizontal scroller and <ref type="type" 
     id="NSScrollArrowPosition">NSScrollerArrowsMaxEnd</ref> if the scroller
     is a vertical scroller. See <ref type="type" id="NSScrollArrowPosition">
     NSScrollArrowPosition</ref> for more informations.</p>
Index: Source/NSMenuView.m
===================================================================
--- Source/NSMenuView.m (revision 24388)
+++ Source/NSMenuView.m (working copy)
@@ -41,6 +41,7 @@
 #include "AppKit/NSImage.h"
 
 #include "GNUstepGUI/GSTitleView.h"
+#include "GNUstepGUI/GSTheme.h"
 
 #include <Foundation/Foundation.h>
 
@@ -1103,7 +1104,7 @@
   NSRectEdge sides[2]; 
   float      grays[] = {NSDarkGray, NSDarkGray};
 
-  if (_horizontal == YES)
+  /*if (_horizontal == YES)
     {
       sides[0] = NSMinYEdge;
       sides[1] = NSMinYEdge;
@@ -1116,7 +1117,10 @@
       // Draw the dark gray upper left lines.
       NSDrawTiledRects(_bounds, rect, sides, grays, 2);
     }
-  
+*/
+  // Draw the menuview background
+  [[GSTheme theme] menuView:self drawBackgroundWithRect:rect];
+
   // Draw the menu cells.
   for (i = 0; i < howMany; i++)
     {
Index: Source/GSTheme_menu.m
===================================================================
--- Source/GSTheme_menu.m       (revision 0)
+++ Source/GSTheme_menu.m       (revision 0)
@@ -0,0 +1,17 @@
+#include "GNUstepGUI/GSTheme.h"
+
address@hidden GSTheme (MenuDrawing)
+
+- (void) menuView:(NSMenuView*)menuView drawBackgroundWithRect:(NSRect)rect
+{
+  // Get background fill image and tile it. Draw a border (optionally?)
+}
+
+- (void) menuItemCell:(NSMenuItemCell*)cell 
+  drawBorderAndBackgroundWithFrame:(NSRect)frame;
+{
+  // Draw the border and background of a menu item cell. Take into account
+  // the present item state (highlighted/not) and preset colours.
+}
address@hidden
+
Index: Headers/AppKit/NSBezierPath.h
===================================================================
--- Headers/AppKit/NSBezierPath.h       (revision 24388)
+++ Headers/AppKit/NSBezierPath.h       (working copy)
@@ -51,10 +51,10 @@
     points are considered outside a path.
     <deflist>
       <term>NSNonZeroWindingRule</term>
-      <desc>A point is inside the path iff the winding count at the point
+      <desc>A point is inside the path if the winding count at the point
       is non-zero.</desc>
       <term>NSEvenOddWindingRule</term>
-      <desc>A point is inside the path iff the winding count at the point
+      <desc>A point is inside the path if the winding count at the point
       is odd.</desc>
     </deflist>
     */
Index: Headers/AppKit/NSScroller.h
===================================================================
--- Headers/AppKit/NSScroller.h (revision 24388)
+++ Headers/AppKit/NSScroller.h (working copy)
@@ -37,12 +37,49 @@
 
 @class NSEvent;
 
+/**
+  * <p>The arrow position describes where in the scroller control the 
+  * arrow buttons are displayed.</p>
+  *
+  * <deflist>
+  *   <term>NSScrollerArrowsMaxEnd</term>
+  *   <desc>Displays the arrow buttons at the bottom or right end of the
+  *         control.</desc>
+  *   <term>NSScrollerArrowsMinEnd</term>
+  *   <desc>Displays the arrows buttons at the top or left end of the
+  *         control.</desc>
+  *   <term>NSScrollerArrowsNone</term>
+  *   <desc>The scroller does not display any arrow buttons.</desc>
+  * </deflist>
+  */
 typedef enum _NSScrollArrowPosition {
   NSScrollerArrowsMaxEnd,
   NSScrollerArrowsMinEnd,
   NSScrollerArrowsNone 
 } NSScrollArrowPosition;
 
+/**
+  * <p>A scroller part is one of the components that make up the scroller
+  * control, such as its knob slot or arrow buttons.</p>
+  * 
+  * <deflist>
+  *   <term>NSScrollerNoPart</term>
+  *   <desc>Not a part of the scroller.</desc>
+  *   <term>NSScrollerDecrementPage</term>
+  *   <desc></desc>
+  *   <term>NSScrollerIncrementPage</term>
+  *   <desc></desc>
+  *   <term>NSScrollerKnob</term>
+  *   <desc>The scroller control knob.</desc>
+  *   <term>NSScrollerKnobSlot</term>
+  *   <desc>The knob slot in which the knob slides in.</desc>
+  *   <term>NSScrollerDecrementLine</term>
+  *   <desc>Part of the scroller that causes movement up or to the left.</desc>
+  *   <term>NSScrollerIncrementLine</term>
+  *   <desc>Part of the scroller that causes movement down or 
+  *         to the right.</desc>
+  * </deflist>
+  */
 typedef enum _NSScrollerPart {
   NSScrollerNoPart = 0,
   NSScrollerDecrementPage,
@@ -53,12 +90,34 @@
   NSScrollerKnobSlot
 } NSScrollerPart;
 
+/**
+  * <p>The usuable scroller parts are those which are visible. It can be
+  * one of the combinations described below.</p>
+  * <deflist>
+  *   <term>NSNoScrollerParts</term>
+  *   <desc>No scroller parts are visible except for the knob slot.</desc>
+  *   <term>NSOnlyScrollerArrows</term>
+  *   <desc>The scroller is showing only its arrow buttons but no knob.</desc>
+  *   <term>NSAllScrollerParts</term>
+  *   <desc>All the scroller parts are visible.</desc>
+  * </deflist>
+  */
 typedef enum _NSScrollerUsablePart {
   NSNoScrollerParts = 0,
   NSOnlyScrollerArrows,
   NSAllScrollerParts  
 } NSUsableScrollerParts;
 
+/**
+  * The button that should be drawn in the scroller.
+  * 
+  * <deflist>
+  * <term>NSScrollerIncrementArrow</term>
+  * <desc>The button that moves the scroller down or to the right.</desc>
+  * <term>NSScrollerDecrementArrow</term>
+  * <desc>The buttont that moves the scroller up to to the left.</desc>
+  * </deflist>
+  */
 typedef enum _NSScrollerArrow {
   NSScrollerIncrementArrow,
   NSScrollerDecrementArrow
Index: Headers/Additions/GNUstepGUI/GSTheme.h
===================================================================
--- Headers/Additions/GNUstepGUI/GSTheme.h      (revision 24388)
+++ Headers/Additions/GNUstepGUI/GSTheme.h      (working copy)
@@ -138,6 +138,8 @@
 // For gradient types
 #include "AppKit/NSButtonCell.h"
 
+#include <AppKit/NSScroller.h>
+
 #if    OS_API_VERSION(GS_API_NONE,GS_API_NONE)
 @class NSArray;
 @class NSBundle;
@@ -495,5 +497,78 @@
                  flipped: (BOOL)flipped;
 @end
 
+/**
+  * High-level drawing methods for buttons. Internal button layout is handled
+  * by the control, so only the border and/or background is configurable.
+  */
address@hidden GSTheme (ButtonDrawing)
+/** Return the size of a button's border. This includes the total width and
+    total height. This method is only called if the cell is bordered or 
bezeled. 
+    You need to take into account the current bezel or border style.*/
+- (NSSize) buttonBorderSize:(NSButtonCell*)cell;
+
+/** Return the frame for drawing the contents of a button. Take into account
+    the size of the border if the cell is bordered. */
+- (NSRect) button:(NSButtonCell*)cell drawingRectForBounds:(NSRect)bounds;
+
+/** Draw the border and background of a button using cellFrame as the outer
+   rectangle. Return the rectangle corresponding to the drawable area. 
+   */
+- (void) button:(NSButtonCell*)cell 
+  drawWithFrame:(NSRect)cellFrame 
+         inView:(NSControl*)controlView
+          style:(int)style
+          state:(GSThemeControlState)state;
+
+/** Draw the focus for cell with frame cellFrame. */
+- (void) button:(NSButtonCell*)cell drawFocusWithRect:(NSRect)cellFrame
+   inView:(NSControl*)controlView;
address@hidden
+
address@hidden NSMenuItem;
address@hidden NSMenuItemCell;
address@hidden NSMenuView;
+/**
+  * High level menu drawing methods for themes. These can be overriden to 
+  * achieve different layouts or interface styles for major controls.
+  * The default implementation uses theme images to draw the menu. 
+  */
address@hidden GSTheme (MenuDrawing)
+
+/**
+  * Draw the background of a menu view. Usually just a fill operation on the 
+  * background of the view. The default implementation uses the theme back
+  * ground image and tiles it.
+  */
+- (void) menuView:(NSMenuView*)menuView drawBackgroundWithRect:(NSRect)rect;
+
+/**
+  * Draw the background and frame of a menu item cell.
+  */
+- (void) menuItemCell:(NSMenuItemCell*)cell
+  drawBorderAndBackgroundWithFrame:(NSRect)aRect
+  inView:(NSMenuView*)view;
+
address@hidden
+
+
address@hidden NSScroller;
+
+/**
+  * Methods for customising the appearance of an NSScroller.
+  */
address@hidden GSTheme (ScrollerDrawing)
+/**
+  * <p>Return the default width of a scroller control.</p>
+  */
+- (float) scrollerWidth;
+
+/**
+  <p>Return the rectangle on a scroller control where a specified part
+    should be drawn. Return NSZeroRect if this part is not to be drawn on
+    the control.</p>
+  */
+- (NSRect) scroller:(NSScroller*)scroller rectForPart:(NSScrollerPart)aPart; 
address@hidden
 #endif /* OS_API_VERSION */
 #endif /* _GNUstep_H_GSTheme */

reply via email to

[Prev in Thread] Current Thread [Next in Thread]