PGItemNotify interface, PGScrollFrame, and more general PGSliderBar
This commit is contained in:
parent
80efd7c253
commit
1e81e656ab
|
|
@ -28,6 +28,7 @@ class DirectButton(DirectFrame):
|
|||
('pgFunc', PGButton, None),
|
||||
('numStates', 4, None),
|
||||
('state', NORMAL, None),
|
||||
('relief', RAISED, None),
|
||||
('invertedFrames', (1,), None),
|
||||
# Command to be called on button click
|
||||
('command', None, None),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ from DirectLabel import *
|
|||
from DirectScrolledList import *
|
||||
from DirectDialog import *
|
||||
from DirectWaitBar import *
|
||||
from DirectSliderBar import *
|
||||
from DirectSlider import *
|
||||
from DirectScrollBar import *
|
||||
from DirectScrolledFrame import *
|
||||
from DirectCheckButton import *
|
||||
from DirectOptionMenu import *
|
||||
|
|
|
|||
|
|
@ -685,6 +685,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
|
|||
('frameSize', None, self.setFrameSize),
|
||||
('frameColor', (.8,.8,.8,1), self.setFrameColor),
|
||||
('frameTexture', None, self.setFrameTexture),
|
||||
('frameVisibleScale', (1,1), self.setFrameVisibleScale),
|
||||
('pad', (0,0), self.resetFrameSize),
|
||||
# Override button id (beware! your name may not be unique!)
|
||||
('guiId', None, INITOPT),
|
||||
|
|
@ -866,6 +867,8 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
|
|||
# Use user specified bounds
|
||||
self.bounds = self['frameSize']
|
||||
#print "%s bounds = %s" % (self.getName(),self.bounds)
|
||||
bw = (0,0)
|
||||
|
||||
else:
|
||||
if fClearFrame and (frameType != PGFrameStyle.TNone):
|
||||
self.frameStyle[0].setType(PGFrameStyle.TNone)
|
||||
|
|
@ -878,11 +881,13 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
|
|||
if (frameType != PGFrameStyle.TNone):
|
||||
self.frameStyle[0].setType(frameType)
|
||||
self.guiItem.setFrameStyle(0, self.frameStyle[0])
|
||||
if ((frameType != PGFrameStyle.TNone) and
|
||||
(frameType != PGFrameStyle.TFlat)):
|
||||
bw = self['borderWidth']
|
||||
else:
|
||||
bw = (0,0)
|
||||
|
||||
if ((frameType != PGFrameStyle.TNone) and
|
||||
(frameType != PGFrameStyle.TFlat)):
|
||||
bw = self['borderWidth']
|
||||
else:
|
||||
bw = (0,0)
|
||||
|
||||
# Set frame to new dimensions
|
||||
self.guiItem.setFrame(
|
||||
self.bounds[0] - bw[0],
|
||||
|
|
@ -974,6 +979,12 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
|
|||
self.frameStyle[i].setTexture(texture)
|
||||
self.updateFrameStyle()
|
||||
|
||||
def setFrameVisibleScale(self):
|
||||
scale = self['frameVisibleScale']
|
||||
for i in range(self['numStates']):
|
||||
self.frameStyle[i].setVisibleScale(scale[0], scale[1])
|
||||
self.updateFrameStyle()
|
||||
|
||||
def setBorderWidth(self):
|
||||
width = self['borderWidth']
|
||||
for i in range(self['numStates']):
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ FrameStyleDict = {'flat' : FLAT, 'raised' : RAISED, 'sunken': SUNKEN,
|
|||
'groove' : GROOVE, 'ridge' : RIDGE
|
||||
}
|
||||
|
||||
# Orientation of DirectSlider and DirectScrollBar
|
||||
HORIZONTAL = 'horizontal'
|
||||
VERTICAL = 'vertical'
|
||||
|
||||
# Dialog button values
|
||||
DIALOG_NO = 0
|
||||
DIALOG_OK = DIALOG_YES = DIALOG_RETRY = 1
|
||||
|
|
@ -55,6 +59,8 @@ OVERFLOW = PGEntry.getOverflowPrefix()
|
|||
ACCEPT = PGEntry.getAcceptPrefix() + KeyboardButton.enter().getName() + '-'
|
||||
TYPE = PGEntry.getTypePrefix()
|
||||
ERASE = PGEntry.getErasePrefix()
|
||||
# For DirectSlider and DirectScrollBar widgets
|
||||
ADJUST = PGSliderBar.getAdjustPrefix()
|
||||
|
||||
|
||||
# For setting the sorting order of a widget's visible components
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
from DirectFrame import *
|
||||
from DirectButton import *
|
||||
from DirectGuiBase import _OPT_VALUE
|
||||
|
||||
"""
|
||||
import DirectScrollBar
|
||||
d = DirectScrollBar(borderWidth=(0,0))
|
||||
|
||||
"""
|
||||
|
||||
class DirectScrollBar(DirectFrame):
|
||||
"""
|
||||
DirectScrollBar -- a widget which represents a scroll bar the user can
|
||||
use for paging through a large document or panel.
|
||||
"""
|
||||
def __init__(self, parent = None, **kw):
|
||||
optiondefs = (
|
||||
# Define type of DirectGuiWidget
|
||||
('pgFunc', PGSliderBar, None),
|
||||
('state', NORMAL, None),
|
||||
('frameColor', (0.6,0.6,0.6,1), None),
|
||||
|
||||
('range', (0, 1), self.setRange),
|
||||
('value', 0, self.__setValue),
|
||||
('pageSize', 0.1, self.setPageSize),
|
||||
('orientation', HORIZONTAL, self.setOrientation),
|
||||
('manageButtons', 1, self.setManageButtons),
|
||||
('resizeThumb', 1, self.setResizeThumb),
|
||||
|
||||
# Function to be called repeatedly as the bar is scrolled
|
||||
('command', None, None),
|
||||
('extraArgs', [], None),
|
||||
)
|
||||
|
||||
if kw.get('orientation') == VERTICAL:
|
||||
# These are the default options for a vertical layout.
|
||||
optiondefs += (
|
||||
('frameSize', (-0.04,0.04,-0.5,0.5), None),
|
||||
)
|
||||
else:
|
||||
# These are the default options for a horizontal layout.
|
||||
optiondefs += (
|
||||
('frameSize', (-0.5,0.5,-0.04,0.04), None),
|
||||
)
|
||||
|
||||
# Merge keyword options with default options
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize superclasses
|
||||
DirectFrame.__init__(self, parent)
|
||||
|
||||
self.thumb = self.createcomponent(
|
||||
"thumb", (), None,
|
||||
DirectButton, (self,),
|
||||
borderWidth = self['borderWidth'])
|
||||
self.incButton = self.createcomponent(
|
||||
"incButton", (), None,
|
||||
DirectButton, (self,),
|
||||
borderWidth = self['borderWidth'])
|
||||
self.decButton = self.createcomponent(
|
||||
"decButton", (), None,
|
||||
DirectButton, (self,),
|
||||
borderWidth = self['borderWidth'])
|
||||
|
||||
self.guiItem.setThumbButton(self.thumb.guiItem)
|
||||
self.guiItem.setLeftButton(self.decButton.guiItem)
|
||||
self.guiItem.setRightButton(self.incButton.guiItem)
|
||||
|
||||
# Bind command function
|
||||
self.bind(ADJUST, self.commandFunc)
|
||||
|
||||
# Call option initialization functions
|
||||
self.initialiseoptions(DirectScrollBar)
|
||||
|
||||
def setRange(self):
|
||||
# Try to preserve the value across a setRange call.
|
||||
v = self['value']
|
||||
r = self['range']
|
||||
self.guiItem.setRange(r[0], r[1])
|
||||
self['value'] = v
|
||||
|
||||
def __setValue(self):
|
||||
# This is the internal function that is called when
|
||||
# self['value'] is directly assigned.
|
||||
self.guiItem.setValue(self['value'])
|
||||
|
||||
def setValue(self, value):
|
||||
# This is the public function that is meant to be called by a
|
||||
# user that doesn't like to use (or doesn't understand) the
|
||||
# preferred interface of self['value'].
|
||||
self['value'] = value
|
||||
|
||||
def getValue(self):
|
||||
return self.guiItem.getValue()
|
||||
|
||||
def getRatio(self):
|
||||
return self.guiItem.getRatio()
|
||||
|
||||
def setPageSize(self):
|
||||
self.guiItem.setPageSize(self['pageSize'])
|
||||
|
||||
def setOrientation(self):
|
||||
if self['orientation'] == HORIZONTAL:
|
||||
self.guiItem.setAxis(Vec3(1, 0, 0))
|
||||
else:
|
||||
self.guiItem.setAxis(Vec3(0, 0, -1))
|
||||
|
||||
def setManageButtons(self):
|
||||
self.guiItem.setManagePieces(self['manageButtons'])
|
||||
|
||||
def setResizeThumb(self):
|
||||
self.guiItem.setResizeThumb(self['resizeThumb'])
|
||||
|
||||
def destroy(self):
|
||||
DirectFrame.destroy(self)
|
||||
|
||||
def commandFunc(self):
|
||||
# Store the updated value in self['value']
|
||||
self._optionInfo['value'][_OPT_VALUE] = self.guiItem.getValue()
|
||||
|
||||
if self['command']:
|
||||
apply(self['command'], self['extraArgs'])
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
from DirectFrame import *
|
||||
from DirectScrollBar import *
|
||||
|
||||
"""
|
||||
import DirectScrolledFrame
|
||||
d = DirectScrolledFrame(borderWidth=(0,0))
|
||||
|
||||
"""
|
||||
|
||||
class DirectScrolledFrame(DirectFrame):
|
||||
"""
|
||||
DirectScrolledFrame -- a special frame that uses DirectScrollBar to
|
||||
implement a small window (the frameSize) into a potentially much
|
||||
larger virtual canvas (the canvasSize, scrolledFrame.getCanvas()).
|
||||
|
||||
Unless specified otherwise, scroll bars are automatically created
|
||||
and managed as needed, based on the relative sizes od the
|
||||
frameSize and the canvasSize. You can also set manageScrollBars =
|
||||
0 and explicitly position and hide or show the scroll bars
|
||||
yourself.
|
||||
"""
|
||||
def __init__(self, parent = None, **kw):
|
||||
optiondefs = (
|
||||
# Define type of DirectGuiWidget
|
||||
('pgFunc', PGScrollFrame, None),
|
||||
('frameSize', (-0.5,0.5,-0.5,0.5), None),
|
||||
|
||||
('canvasSize', (-1,1,-1,1), self.setCanvasSize),
|
||||
('manageScrollBars', 1, self.setManageScrollBars),
|
||||
('autoHideScrollBars', 1, self.setAutoHideScrollBars),
|
||||
('scrollBarWidth', 0.08, None),
|
||||
)
|
||||
|
||||
# Merge keyword options with default options
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize superclasses
|
||||
DirectFrame.__init__(self, parent)
|
||||
|
||||
# The scrollBarWidth parameter is just used at scroll bar
|
||||
# construction time, and supplies a default frame. It does
|
||||
# not override an explicit frame specified on the scroll bar.
|
||||
# If you want to change the frame width after construction,
|
||||
# you must specify their frameSize tuples explicitly.
|
||||
w = self['scrollBarWidth']
|
||||
|
||||
self.verticalScroll = self.createcomponent(
|
||||
"verticalScroll", (), None,
|
||||
DirectScrollBar, (self,),
|
||||
borderWidth = self['borderWidth'],
|
||||
frameSize = (-w / 2.0, w / 2.0, -1, 1),
|
||||
orientation = VERTICAL)
|
||||
|
||||
self.horizontalScroll = self.createcomponent(
|
||||
"horizontalScroll", (), None,
|
||||
DirectScrollBar, (self,),
|
||||
borderWidth = self['borderWidth'],
|
||||
frameSize = (-1, 1, -w / 2.0, w / 2.0),
|
||||
orientation = HORIZONTAL)
|
||||
|
||||
self.guiItem.setVerticalSlider(self.verticalScroll.guiItem)
|
||||
self.guiItem.setHorizontalSlider(self.horizontalScroll.guiItem)
|
||||
|
||||
self.canvas = NodePath(self.guiItem.getCanvasNode())
|
||||
|
||||
# Call option initialization functions
|
||||
self.initialiseoptions(DirectScrolledFrame)
|
||||
|
||||
def setCanvasSize(self):
|
||||
f = self['canvasSize']
|
||||
self.guiItem.setVirtualFrame(f[0], f[1], f[2], f[3])
|
||||
|
||||
def getCanvas(self):
|
||||
return self.canvas
|
||||
|
||||
def setManageScrollBars(self):
|
||||
self.guiItem.setManagePieces(self['manageScrollBars'])
|
||||
|
||||
def setAutoHideScrollBars(self):
|
||||
self.guiItem.setAutoHide(self['autoHideScrollBars'])
|
||||
|
||||
def destroy(self):
|
||||
DirectFrame.destroy(self)
|
||||
|
||||
def commandFunc(self):
|
||||
if self['command']:
|
||||
apply(self['command'], self['extraArgs'])
|
||||
|
||||
def destroy(self):
|
||||
# Destroy children of the canvas
|
||||
for child in self.canvas.getChildrenAsList():
|
||||
childGui = self.guiDict.get(child.getName())
|
||||
if childGui: childGui.destroy()
|
||||
DirectFrame.DirectFrame.destroy(self)
|
||||
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
from DirectFrame import *
|
||||
from DirectButton import *
|
||||
from DirectGuiBase import _OPT_VALUE
|
||||
|
||||
"""
|
||||
import DirectSlider
|
||||
d = DirectSlider(borderWidth=(0,0))
|
||||
|
||||
"""
|
||||
|
||||
class DirectSlider(DirectFrame):
|
||||
"""
|
||||
DirectSlider -- a widget which represents a slider that the
|
||||
user can pull left and right to represent a continuous value.
|
||||
"""
|
||||
def __init__(self, parent = None, **kw):
|
||||
optiondefs = (
|
||||
# Define type of DirectGuiWidget
|
||||
('pgFunc', PGSliderBar, None),
|
||||
('state', NORMAL, None),
|
||||
('frameColor', (0.6,0.6,0.6,1), None),
|
||||
|
||||
('range', (0, 1), self.setRange),
|
||||
('value', 0, self.__setValue),
|
||||
('pageSize', 0.1, self.setPageSize),
|
||||
('orientation', HORIZONTAL, self.setOrientation),
|
||||
|
||||
# Function to be called repeatedly as slider is moved
|
||||
('command', None, None),
|
||||
('extraArgs', [], None),
|
||||
)
|
||||
|
||||
if kw.get('orientation') == VERTICAL:
|
||||
# These are the default options for a vertical layout.
|
||||
optiondefs += (
|
||||
('frameSize', (-0.08,0.08,-1,1), None),
|
||||
('frameVisibleScale', (0.25,1), None),
|
||||
)
|
||||
else:
|
||||
# These are the default options for a horizontal layout.
|
||||
optiondefs += (
|
||||
('frameSize', (-1,1,-0.08,0.08), None),
|
||||
('frameVisibleScale', (1,0.25), None),
|
||||
)
|
||||
|
||||
# Merge keyword options with default options
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize superclasses
|
||||
DirectFrame.__init__(self, parent)
|
||||
|
||||
self.thumb = self.createcomponent("thumb", (), None,
|
||||
DirectButton, (self,),
|
||||
borderWidth = self['borderWidth'])
|
||||
if self.thumb['frameSize'] == None and \
|
||||
self.thumb.bounds == [0.0, 0.0, 0.0, 0.0]:
|
||||
# Compute a default frameSize for the thumb.
|
||||
f = self['frameSize']
|
||||
if self['orientation'] == HORIZONTAL:
|
||||
self.thumb['frameSize'] = (f[0]*0.05,f[1]*0.05,f[2],f[3])
|
||||
else:
|
||||
self.thumb['frameSize'] = (f[0],f[1],f[2]*0.05,f[3]*0.05)
|
||||
|
||||
self.guiItem.setThumbButton(self.thumb.guiItem)
|
||||
|
||||
# Bind command function
|
||||
self.bind(ADJUST, self.commandFunc)
|
||||
|
||||
# Call option initialization functions
|
||||
self.initialiseoptions(DirectSlider)
|
||||
|
||||
def setRange(self):
|
||||
# Try to preserve the value across a setRange call.
|
||||
v = self['value']
|
||||
r = self['range']
|
||||
self.guiItem.setRange(r[0], r[1])
|
||||
self['value'] = v
|
||||
|
||||
def __setValue(self):
|
||||
# This is the internal function that is called when
|
||||
# self['value'] is directly assigned.
|
||||
self.guiItem.setValue(self['value'])
|
||||
|
||||
def setValue(self, value):
|
||||
# This is the public function that is meant to be called by a
|
||||
# user that doesn't like to use (or doesn't understand) the
|
||||
# preferred interface of self['value'].
|
||||
self['value'] = value
|
||||
|
||||
def getValue(self):
|
||||
return self.guiItem.getValue()
|
||||
|
||||
def getRatio(self):
|
||||
return self.guiItem.getRatio()
|
||||
|
||||
def setPageSize(self):
|
||||
self.guiItem.setPageSize(self['pageSize'])
|
||||
|
||||
def setOrientation(self):
|
||||
if self['orientation'] == HORIZONTAL:
|
||||
self.guiItem.setAxis(Vec3(1, 0, 0))
|
||||
else:
|
||||
self.guiItem.setAxis(Vec3(0, 0, 1))
|
||||
|
||||
def destroy(self):
|
||||
DirectFrame.destroy(self)
|
||||
|
||||
def commandFunc(self):
|
||||
# Store the updated value in self['value']
|
||||
self._optionInfo['value'][_OPT_VALUE] = self.guiItem.getValue()
|
||||
|
||||
if self['command']:
|
||||
apply(self['command'], self['extraArgs'])
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
from DirectButton import *
|
||||
from DirectFrame import *
|
||||
|
||||
"""
|
||||
import DirectSliderBar
|
||||
d = DirectSliderBar(borderWidth=(0,0))
|
||||
|
||||
"""
|
||||
|
||||
class DirectSliderButton(DirectButton):
|
||||
def __init__(self, parent = None, **kw):
|
||||
optiondefs = (
|
||||
# Define type of DirectGuiWidget
|
||||
('pgFunc', PGSliderButton, None),
|
||||
)
|
||||
# Merge keyword options with default options
|
||||
self.defineoptions(kw, optiondefs)
|
||||
# Initialize superclasses
|
||||
DirectButton.__init__(self,parent)
|
||||
# Call option initialization functions
|
||||
self.initialiseoptions(DirectSliderButton)
|
||||
|
||||
class DirectSliderBar(DirectFrame):
|
||||
"""
|
||||
DirectEntry(parent) - Create a DirectGuiWidget which responds
|
||||
to keyboard buttons
|
||||
"""
|
||||
def __init__(self, parent = None, **kw):
|
||||
# Inherits from DirectFrame
|
||||
# A Direct Frame can have:
|
||||
# - A background texture (pass in path to image, or Texture Card)
|
||||
# - A midground geometry item (pass in geometry)
|
||||
# - A foreground text Node (pass in text string or Onscreen Text)
|
||||
optiondefs = (
|
||||
# Define type of DirectGuiWidget
|
||||
('pgFunc', PGSliderBar, None),
|
||||
('width', 10, None),
|
||||
('height', 1, None),
|
||||
('button', None, None),
|
||||
('sliderOnly', 0, self.setSliderOnly),
|
||||
('negativeMapping',0, self.setNegativeMapping),
|
||||
('range', 100, self.setRange),
|
||||
('value', 0, self.setValue),
|
||||
('barBorderWidth', (0,0), self.setBarBorderWidth),
|
||||
('barColor', (1,0,0,1), self.setBarColor),
|
||||
('barRelief', FLAT, self.setBarRelief),
|
||||
('active', 0, self.setActive),
|
||||
('sortOrder', NO_FADE_SORT_INDEX, None),
|
||||
# Command to be called on button movement
|
||||
('command', None, None),
|
||||
('extraArgs', [], None),
|
||||
)
|
||||
if kw.has_key('text'):
|
||||
textoptiondefs = (
|
||||
('text_pos', (0,-0.025), None),
|
||||
('text_scale', 0.1, None),
|
||||
('text_fg', (1,1,1,1), None),
|
||||
('text_shadow', (0,0,0,1), None),
|
||||
('text_align', TextNode.ALeft, None)
|
||||
)
|
||||
else:
|
||||
textoptiondefs = ()
|
||||
# Merge keyword options with default options
|
||||
self.defineoptions(kw, optiondefs + textoptiondefs)
|
||||
# Initialize superclasses
|
||||
DirectFrame.__init__(self, parent)
|
||||
self.barStyle = PGFrameStyle()
|
||||
# Call option initialization functions
|
||||
self.initialiseoptions(DirectSliderBar)
|
||||
|
||||
if (self['button'] != None):
|
||||
self.guiItem.setSliderButton(self['button'], self['button'].guiItem)
|
||||
|
||||
if (self['image'] != None):
|
||||
self.guiItem.setScale(self['image_scale'][0])
|
||||
self.guiItem.setup(self.getWidth(), self.getHeight(), self['range'])
|
||||
else:
|
||||
#figure out what is happening?????
|
||||
#self.guiItem.setState(0)
|
||||
#self.guiItem.clearStateDef(0)
|
||||
self.guiItem.setFrame(-3.0, 3.0, -0.125, 0.125)
|
||||
self.barStyle.setWidth(0.05, 0.05)
|
||||
self.barStyle.setColor(0.6,0.6,0.6,1)
|
||||
self.barStyle.setType(PGFrameStyle.TBevelIn)
|
||||
self.guiItem.setFrameStyle(0, self.barStyle)
|
||||
self.guiItem.setScale(2)
|
||||
self.guiItem.setup(6, 0.5, self['range'])
|
||||
self.guiItem.setValue(self['value'])
|
||||
if (self['scale'] != None):
|
||||
self.setScale(self['scale'])
|
||||
else:
|
||||
self.setScale(0.1)
|
||||
|
||||
self.guiItem.setActive(1)
|
||||
|
||||
#self.barStyle.setColor(0.8,0.8,0.8,1)
|
||||
#self.barStyle.setType(PGFrameStyle.TBevelOut)
|
||||
#self.updateBarStyle()
|
||||
|
||||
if (self['command'] != None):
|
||||
# Attach command function to slider button movement
|
||||
self.bind('updated-slider-', self.commandFunc)
|
||||
|
||||
def destroy(self):
|
||||
del self.barStyle
|
||||
DirectFrame.destroy(self)
|
||||
|
||||
def setSliderOnly(self):
|
||||
self.guiItem.setSliderOnly(self['sliderOnly'])
|
||||
|
||||
def setNegativeMapping(self):
|
||||
self.guiItem.setNegativeMapping(self['negativeMapping'])
|
||||
|
||||
def setRange(self):
|
||||
self.guiItem.setRange(self['range'])
|
||||
|
||||
def setValue(self):
|
||||
self.guiItem.setValue(self['value'])
|
||||
|
||||
def getPercent(self):
|
||||
return self.guiItem.getPercent()
|
||||
|
||||
def updateBarStyle(self):
|
||||
if not self.fInit:
|
||||
self.guiItem.setBarStyle(self.barStyle)
|
||||
|
||||
def setBarRelief(self):
|
||||
self.barStyle.setType(self['barRelief'])
|
||||
self.updateBarStyle()
|
||||
|
||||
def setBarBorderWidth(self):
|
||||
self.barStyle.setWidth(*self['barBorderWidth'])
|
||||
self.updateBarStyle()
|
||||
|
||||
def setBarColor(self):
|
||||
color = self['barColor']
|
||||
self.barStyle.setColor(color[0], color[1], color[2], color[3])
|
||||
self.updateBarStyle()
|
||||
|
||||
def setActive(self):
|
||||
self.guiItem.setActive(self['active'])
|
||||
|
||||
def commandFunc(self):
|
||||
if self['command']:
|
||||
# Pass any extra args to command
|
||||
apply(self['command'], self['extraArgs'])
|
||||
|
||||
|
|
@ -230,10 +230,6 @@ write(ostream &out, int indent_level) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionEntry::
|
||||
check_clip_planes() {
|
||||
const RenderAttrib *cpa_attrib =
|
||||
_into_node_path.get_net_state()->get_attrib(ClipPlaneAttrib::get_class_type());
|
||||
if (cpa_attrib != (const RenderAttrib *)NULL) {
|
||||
_into_clip_planes = DCAST(ClipPlaneAttrib, cpa_attrib);
|
||||
}
|
||||
_into_clip_planes = _into_node_path.get_net_state()->get_clip_plane();
|
||||
_flags |= F_checked_clip_planes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#include "datagramIterator.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "omniBoundingVolume.h"
|
||||
#include "boundingPlane.h"
|
||||
#include "geom.h"
|
||||
#include "geomTrifans.h"
|
||||
#include "geomLinestrips.h"
|
||||
|
|
@ -94,11 +94,10 @@ output(ostream &out) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionPlane::
|
||||
recompute_bound() {
|
||||
// Planes always have an infinite bounding volume.
|
||||
BoundedObject::recompute_bound();
|
||||
// Less than ideal: we throw away whatever we just allocated in
|
||||
// BoundedObject.
|
||||
return set_bound_ptr(new OmniBoundingVolume);
|
||||
return set_bound_ptr(new BoundingPlane(_plane));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -279,9 +279,8 @@ get_collision_origin() const {
|
|||
PT(PandaNode) CollisionPolygon::
|
||||
get_viz(const CullTraverser *trav, const CullTraverserData &data,
|
||||
bool bounds_only) const {
|
||||
const RenderAttrib *cpa_attrib =
|
||||
data._state->get_attrib(ClipPlaneAttrib::get_class_type());
|
||||
if (cpa_attrib == (const RenderAttrib *)NULL) {
|
||||
const ClipPlaneAttrib *cpa = data._state->get_clip_plane();
|
||||
if (cpa == (const ClipPlaneAttrib *)NULL) {
|
||||
// Fortunately, the polygon is not clipped. This is the normal,
|
||||
// easy case.
|
||||
return CollisionSolid::get_viz(trav, data, bounds_only);
|
||||
|
|
@ -289,7 +288,7 @@ get_viz(const CullTraverser *trav, const CullTraverserData &data,
|
|||
|
||||
if (collide_cat.is_debug()) {
|
||||
collide_cat.debug()
|
||||
<< "drawing polygon with clip plane " << *cpa_attrib << "\n";
|
||||
<< "drawing polygon with clip plane " << *cpa << "\n";
|
||||
}
|
||||
|
||||
// The polygon is clipped. We need to render it clipped. We could
|
||||
|
|
@ -298,7 +297,6 @@ get_viz(const CullTraverser *trav, const CullTraverserData &data,
|
|||
// and clip it by hand instead, just to prove that our clipping
|
||||
// algorithm works properly. This does require some more dynamic
|
||||
// work.
|
||||
const ClipPlaneAttrib *cpa = DCAST(ClipPlaneAttrib, cpa_attrib);
|
||||
Points new_points;
|
||||
if (apply_clip_plane(new_points, cpa, data.get_net_transform(trav))) {
|
||||
// All points are behind the clip plane; just draw the original
|
||||
|
|
@ -1093,15 +1091,21 @@ clip_polygon(CollisionPolygon::Points &new_points,
|
|||
const LPoint2f &this_point = (*pi)._p;
|
||||
bool this_is_in = !is_right(this_point - from2d, delta2d);
|
||||
|
||||
if (this_is_in != last_is_in) {
|
||||
// There appears to be a compiler bug in gcc 4.0: we need to
|
||||
// extract this comparison outside of the if statement.
|
||||
bool crossed_over = (this_is_in != last_is_in);
|
||||
if (crossed_over) {
|
||||
// We have just crossed over the clipping line. Find the point
|
||||
// of intersection.
|
||||
LVector2f d = this_point - last_point;
|
||||
float t = -(a * last_point[0] + b * last_point[1] + c) / (a * d[0] + b * d[1]);
|
||||
LPoint2f p = last_point + t * d;
|
||||
float denom = (a * d[0] + b * d[1]);
|
||||
if (denom != 0.0) {
|
||||
float t = -(a * last_point[0] + b * last_point[1] + c) / denom;
|
||||
LPoint2f p = last_point + t * d;
|
||||
|
||||
new_points.push_back(PointDef(p[0], p[1]));
|
||||
last_is_in = this_is_in;
|
||||
new_points.push_back(PointDef(p[0], p[1]));
|
||||
last_is_in = this_is_in;
|
||||
}
|
||||
}
|
||||
|
||||
if (this_is_in) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "depthOffsetAttrib.h"
|
||||
#include "colorScaleAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
|
||||
|
||||
#ifdef DO_COLLISION_RECORDING
|
||||
|
|
@ -137,7 +138,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
xform_data._modelview_transform = trav->get_world_transform();
|
||||
xform_data.apply_transform_and_state(trav, net_transform,
|
||||
RenderState::make_empty(),
|
||||
RenderEffects::make_empty());
|
||||
RenderEffects::make_empty(),
|
||||
ClipPlaneAttrib::make());
|
||||
|
||||
// Draw all the collision solids.
|
||||
Solids::const_iterator si;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@
|
|||
|
||||
#define SOURCES \
|
||||
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
|
||||
boundingLine.h boundingSphere.I boundingSphere.h \
|
||||
boundingLine.h \
|
||||
boundingPlane.I boundingPlane.h \
|
||||
boundingSphere.I boundingSphere.h \
|
||||
boundingVolume.I boundingVolume.h config_mathutil.h \
|
||||
fftCompressor.h finiteBoundingVolume.h frustum.h \
|
||||
frustum_src.I frustum_src.h geometricBoundingVolume.I \
|
||||
|
|
@ -24,7 +26,9 @@
|
|||
plane_src.h rotate_to.h rotate_to_src.cxx
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
boundingHexahedron.cxx boundingLine.cxx boundingSphere.cxx \
|
||||
boundingHexahedron.cxx boundingLine.cxx \
|
||||
boundingPlane.cxx \
|
||||
boundingSphere.cxx \
|
||||
boundingVolume.cxx config_mathutil.cxx fftCompressor.cxx \
|
||||
finiteBoundingVolume.cxx geometricBoundingVolume.cxx \
|
||||
look_at.cxx \
|
||||
|
|
@ -33,7 +37,9 @@
|
|||
|
||||
#define INSTALL_HEADERS \
|
||||
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
|
||||
boundingLine.h boundingSphere.I boundingSphere.h boundingVolume.I \
|
||||
boundingLine.h \
|
||||
boundingPlane.I boundingPlane.h \
|
||||
boundingSphere.I boundingSphere.h boundingVolume.I \
|
||||
boundingVolume.h config_mathutil.h fftCompressor.h \
|
||||
finiteBoundingVolume.h frustum.h frustum_src.I frustum_src.h \
|
||||
geometricBoundingVolume.I geometricBoundingVolume.h look_at.h \
|
||||
|
|
|
|||
39
panda/src/pgui/pgSliderButton.I → panda/src/mathutil/boundingPlane.I
Executable file → Normal file
39
panda/src/pgui/pgSliderButton.I → panda/src/mathutil/boundingPlane.I
Executable file → Normal file
|
|
@ -1,5 +1,5 @@
|
|||
// Filename: pgButton.I
|
||||
// Created by: masad (21Oct04)
|
||||
// Filename: boundingPlane.I
|
||||
// Created by: drose (19Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
@ -16,32 +16,37 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::is_drag_n_drop
|
||||
// Function: BoundingPlane::Default Constructor
|
||||
// Access: Published
|
||||
// Description: Returns if this button is drag_n_drop kind
|
||||
// Description: Constructs an empty "plane" that has no
|
||||
// intersections.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGSliderButton::
|
||||
is_drag_n_drop() {
|
||||
return _drag_n_drop;
|
||||
INLINE_MATHUTIL BoundingPlane::
|
||||
BoundingPlane() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::set_drag_n_drop
|
||||
// Function: BoundingPlane::Constructor
|
||||
// Access: Published
|
||||
// Description: Makes this button a drag_n_drop kind
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderButton::
|
||||
set_drag_n_drop(bool value) {
|
||||
_drag_n_drop = value;
|
||||
INLINE_MATHUTIL BoundingPlane::
|
||||
BoundingPlane(const Planef &plane) :
|
||||
_plane(plane)
|
||||
{
|
||||
_flags = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::set_slider_bar
|
||||
// Function: BoundingPlane::get_plane
|
||||
// Access: Published
|
||||
// Description: Store a copy of the controlling slider bar item
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderButton::
|
||||
set_slider_bar(PGItem *item) {
|
||||
_slider_bar = item;
|
||||
INLINE_MATHUTIL const Planef &BoundingPlane::
|
||||
get_plane() const {
|
||||
nassertr(!is_empty(), _plane);
|
||||
nassertr(!is_infinite(), _plane);
|
||||
return _plane;
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
// Filename: boundingPlane.cxx
|
||||
// Created by: drose (19Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "boundingPlane.h"
|
||||
#include "boundingSphere.h"
|
||||
#include "config_mathutil.h"
|
||||
|
||||
TypeHandle BoundingPlane::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *BoundingPlane::
|
||||
make_copy() const {
|
||||
return new BoundingPlane(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::get_approx_center
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LPoint3f BoundingPlane::
|
||||
get_approx_center() const {
|
||||
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
|
||||
nassertr(!is_infinite(), LPoint3f(0.0f, 0.0f, 0.0f));
|
||||
return _plane.get_point();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::xform
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BoundingPlane::
|
||||
xform(const LMatrix4f &mat) {
|
||||
nassertv(!mat.is_nan());
|
||||
|
||||
if (!is_empty() && !is_infinite()) {
|
||||
_plane.xform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BoundingPlane::
|
||||
output(ostream &out) const {
|
||||
if (is_empty()) {
|
||||
out << "bplane, empty";
|
||||
} else if (is_infinite()) {
|
||||
out << "bplane, infinite";
|
||||
} else {
|
||||
out << "bplane: " << _plane;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::extend_other
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BoundingPlane::
|
||||
extend_other(BoundingVolume *other) const {
|
||||
return other->extend_by_plane(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::around_other
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BoundingPlane::
|
||||
around_other(BoundingVolume *other,
|
||||
const BoundingVolume **first,
|
||||
const BoundingVolume **last) const {
|
||||
return other->around_planes(first, last);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::contains_other
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int BoundingPlane::
|
||||
contains_other(const BoundingVolume *other) const {
|
||||
return other->contains_plane(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::extend_by_plane
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BoundingPlane::
|
||||
extend_by_plane(const BoundingPlane *plane) {
|
||||
nassertr(!plane->is_empty() && !plane->is_infinite(), false);
|
||||
nassertr(!is_infinite(), false);
|
||||
|
||||
if (is_empty()) {
|
||||
_plane = plane->get_plane();
|
||||
_flags = 0;
|
||||
} else {
|
||||
_flags = F_infinite;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingPlane::contains_sphere
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int BoundingPlane::
|
||||
contains_sphere(const BoundingSphere *sphere) const {
|
||||
nassertr(!is_empty() && !is_infinite(), 0);
|
||||
nassertr(!sphere->is_empty() && !sphere->is_infinite(), 0);
|
||||
|
||||
float r = sphere->get_radius();
|
||||
float d = _plane.dist_to_plane(sphere->get_center());
|
||||
|
||||
if (d <= -r) {
|
||||
// The sphere is completely behind the plane.
|
||||
return IF_all | IF_possible | IF_some;
|
||||
|
||||
} else if (d <= r) {
|
||||
// The sphere is intersecting with the plane itself.
|
||||
return IF_possible | IF_some;
|
||||
|
||||
} else {
|
||||
// The sphere is completely in front of the plane.
|
||||
return IF_no_intersection;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// Filename: boundingPlane.h
|
||||
// Created by: drose (19Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOUNDINGPLANE_H
|
||||
#define BOUNDINGPLANE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "geometricBoundingVolume.h"
|
||||
#include "plane.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : BoundingPlane
|
||||
// Description : This funny bounding volume is an infinite plane that
|
||||
// divides space into two regions: the part behind the
|
||||
// normal, which is "inside" the bounding volume, and
|
||||
// the part in front of the normal, which is "outside"
|
||||
// the bounding volume.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA BoundingPlane : public GeometricBoundingVolume {
|
||||
PUBLISHED:
|
||||
INLINE_MATHUTIL BoundingPlane();
|
||||
INLINE_MATHUTIL BoundingPlane(const Planef &plane);
|
||||
|
||||
public:
|
||||
virtual BoundingVolume *make_copy() const;
|
||||
|
||||
virtual LPoint3f get_approx_center() const;
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE_MATHUTIL const Planef &get_plane() const;
|
||||
|
||||
protected:
|
||||
virtual bool extend_other(BoundingVolume *other) const;
|
||||
virtual bool around_other(BoundingVolume *other,
|
||||
const BoundingVolume **first,
|
||||
const BoundingVolume **last) const;
|
||||
virtual int contains_other(const BoundingVolume *other) const;
|
||||
|
||||
virtual bool extend_by_plane(const BoundingPlane *plane);
|
||||
|
||||
virtual int contains_sphere(const BoundingSphere *sphere) const;
|
||||
|
||||
private:
|
||||
Planef _plane;
|
||||
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
GeometricBoundingVolume::init_type();
|
||||
register_type(_type_handle, "BoundingPlane",
|
||||
GeometricBoundingVolume::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "boundingPlane.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -119,6 +119,19 @@ extend_by_line(const BoundingLine *) {
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingVolume::extend_by_plane
|
||||
// Access: Protected, Virtual
|
||||
// Description: Double-dispatch support: called by extend_other()
|
||||
// when the type we're extending by is known to be a
|
||||
// plane.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BoundingVolume::
|
||||
extend_by_plane(const BoundingPlane *) {
|
||||
_flags = F_infinite;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingVolume::around_spheres
|
||||
// Access: Protected, Virtual
|
||||
|
|
@ -167,6 +180,28 @@ around_lines(const BoundingVolume **, const BoundingVolume **) {
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingVolume::around_planes
|
||||
// Access: Protected, Virtual
|
||||
// Description: Double-dispatch support: called by around_other()
|
||||
// when the type of the first element in the list is
|
||||
// known to be a nonempty plane.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BoundingVolume::
|
||||
around_planes(const BoundingVolume **, const BoundingVolume **) {
|
||||
_flags = F_infinite;
|
||||
if (is_of_type(FiniteBoundingVolume::get_class_type())) {
|
||||
// If it's a FiniteBoundingVolume, we can't do any better than
|
||||
// making it infinite. So we return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we might do better, and we require each class to
|
||||
// define a function. If we get here, the function isn't defined,
|
||||
// so we return false to indicate this.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingVolume::contains_sphere
|
||||
// Access: Protected, Virtual
|
||||
|
|
@ -202,3 +237,15 @@ int BoundingVolume::
|
|||
contains_line(const BoundingLine *) const {
|
||||
return IF_dont_understand;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BoundingVolume::contains_plane
|
||||
// Access: Protected, Virtual
|
||||
// Description: Double-dispatch support: called by contains_other()
|
||||
// when the type we're testing for intersection is known
|
||||
// to be a plane.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int BoundingVolume::
|
||||
contains_plane(const BoundingPlane *) const {
|
||||
return IF_dont_understand;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
class BoundingSphere;
|
||||
class BoundingHexahedron;
|
||||
class BoundingLine;
|
||||
class BoundingPlane;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -118,6 +119,7 @@ protected:
|
|||
virtual bool extend_by_sphere(const BoundingSphere *sphere);
|
||||
virtual bool extend_by_hexahedron(const BoundingHexahedron *hexahedron);
|
||||
virtual bool extend_by_line(const BoundingLine *line);
|
||||
virtual bool extend_by_plane(const BoundingPlane *plane);
|
||||
|
||||
virtual bool around_spheres(const BoundingVolume **first,
|
||||
const BoundingVolume **last);
|
||||
|
|
@ -125,10 +127,13 @@ protected:
|
|||
const BoundingVolume **last);
|
||||
virtual bool around_lines(const BoundingVolume **first,
|
||||
const BoundingVolume **last);
|
||||
virtual bool around_planes(const BoundingVolume **first,
|
||||
const BoundingVolume **last);
|
||||
|
||||
virtual int contains_sphere(const BoundingSphere *sphere) const;
|
||||
virtual int contains_hexahedron(const BoundingHexahedron *hexahedron) const;
|
||||
virtual int contains_line(const BoundingLine *line) const;
|
||||
virtual int contains_plane(const BoundingPlane *plane) const;
|
||||
|
||||
|
||||
public:
|
||||
|
|
@ -151,6 +156,7 @@ private:
|
|||
friend class BoundingSphere;
|
||||
friend class BoundingHexahedron;
|
||||
friend class BoundingLine;
|
||||
friend class BoundingPlane;
|
||||
};
|
||||
|
||||
INLINE_MATHUTIL ostream &operator << (ostream &out, const BoundingVolume &bound);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "boundingSphere.h"
|
||||
#include "boundingHexahedron.h"
|
||||
#include "boundingLine.h"
|
||||
#include "boundingPlane.h"
|
||||
#include "linmath_events.h"
|
||||
#include "dconfig.h"
|
||||
#include "pandaSystem.h"
|
||||
|
|
@ -51,6 +52,7 @@ ConfigureFn(config_mathutil) {
|
|||
GeometricBoundingVolume::init_type();
|
||||
OmniBoundingVolume::init_type();
|
||||
BoundingLine::init_type();
|
||||
BoundingPlane::init_type();
|
||||
EventStoreVec2::init_type("EventStoreVec2");
|
||||
EventStoreVec3::init_type("EventStoreVec3");
|
||||
EventStoreMat4::init_type("EventStoreMat4");
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "boundingVolume.cxx"
|
||||
#include "boundingHexahedron.cxx"
|
||||
#include "boundingLine.cxx"
|
||||
#include "boundingPlane.cxx"
|
||||
#include "boundingSphere.cxx"
|
||||
#include "finiteBoundingVolume.cxx"
|
||||
#include "geometricBoundingVolume.cxx"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
// It's not clear how useful a default plane is.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE_MATHUTIL FLOATNAME(Plane)::
|
||||
FLOATNAME(Plane)(void) {
|
||||
FLOATNAME(Plane)() {
|
||||
_v.v._0 = 0.0f;
|
||||
_v.v._1 = 0.0f;
|
||||
_v.v._2 = 1.0f;
|
||||
|
|
@ -116,6 +116,26 @@ operator * (const FLOATNAME(LMatrix4) &mat) const {
|
|||
return FLOATNAME(Plane)(new_normal, new_point);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Plane::Operator *= LMatrix4
|
||||
// Access: Published
|
||||
// Description: Transforms the plane by the indicated matrix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE_MATHUTIL void FLOATNAME(Plane)::
|
||||
operator *= (const FLOATNAME(LMatrix4) &mat) {
|
||||
(*this) = (*this) * mat;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Plane::xform
|
||||
// Access: Published
|
||||
// Description: Transforms the plane by the indicated matrix.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FLOATNAME(Plane)::
|
||||
xform(const FLOATNAME(LMatrix4) &mat) {
|
||||
(*this) = (*this) * mat;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Plane::Unary -
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
// mirror.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
FLOATNAME(LMatrix4) FLOATNAME(Plane)::
|
||||
get_reflection_mat(void) const {
|
||||
get_reflection_mat() const {
|
||||
FLOATTYPE aa = _v.v._0 * _v.v._0;
|
||||
FLOATTYPE ab = _v.v._0 * _v.v._1;
|
||||
FLOATTYPE ac = _v.v._0 * _v.v._2;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA FLOATNAME(Plane) : public FLOATNAME(LVecBase4) {
|
||||
PUBLISHED:
|
||||
INLINE_MATHUTIL FLOATNAME(Plane)(void);
|
||||
INLINE_MATHUTIL FLOATNAME(Plane)();
|
||||
INLINE_MATHUTIL FLOATNAME(Plane)(const FLOATNAME(LVecBase4) ©);
|
||||
INLINE_MATHUTIL FLOATNAME(Plane)(const FLOATNAME(LPoint3) &a,
|
||||
const FLOATNAME(LPoint3) &b,
|
||||
|
|
@ -35,20 +35,22 @@ PUBLISHED:
|
|||
|
||||
INLINE_MATHUTIL FLOATNAME(Plane) operator * (const FLOATNAME(LMatrix3) &mat) const;
|
||||
INLINE_MATHUTIL FLOATNAME(Plane) operator * (const FLOATNAME(LMatrix4) &mat) const;
|
||||
INLINE_MATHUTIL void operator *= (const FLOATNAME(LMatrix4) &mat);
|
||||
INLINE_MATHUTIL void xform(const FLOATNAME(LMatrix4) &mat);
|
||||
INLINE_MATHUTIL FLOATNAME(Plane) operator - () const;
|
||||
|
||||
FLOATNAME(LMatrix4) get_reflection_mat(void) const;
|
||||
FLOATNAME(LMatrix4) get_reflection_mat() const;
|
||||
|
||||
INLINE_MATHUTIL FLOATNAME(LVector3) get_normal() const;
|
||||
FLOATNAME(LPoint3) get_point() const;
|
||||
|
||||
INLINE_MATHUTIL FLOATTYPE dist_to_plane(const FLOATNAME(LPoint3) &point) const;
|
||||
INLINE_MATHUTIL bool intersects_line(FLOATNAME(LPoint3) &intersection_point,
|
||||
const FLOATNAME(LPoint3) &p1,
|
||||
const FLOATNAME(LPoint3) &p2) const;
|
||||
const FLOATNAME(LPoint3) &p1,
|
||||
const FLOATNAME(LPoint3) &p2) const;
|
||||
INLINE_MATHUTIL bool intersects_line(FLOATTYPE &t,
|
||||
const FLOATNAME(LPoint3) &from,
|
||||
const FLOATNAME(LVector3) &delta) const;
|
||||
const FLOATNAME(LPoint3) &from,
|
||||
const FLOATNAME(LVector3) &delta) const;
|
||||
|
||||
bool intersects_plane(FLOATNAME(LPoint3) &from,
|
||||
FLOATNAME(LVector3) &delta,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
cullBinUnsorted.I cullBinUnsorted.h \
|
||||
cullFaceAttrib.I cullFaceAttrib.h \
|
||||
cullHandler.I cullHandler.h \
|
||||
cullPlanes.I cullPlanes.h \
|
||||
cullResult.I cullResult.h \
|
||||
cullTraverser.I cullTraverser.h \
|
||||
cullTraverserData.I cullTraverserData.h \
|
||||
|
|
@ -134,6 +135,7 @@
|
|||
cullBinUnsorted.cxx \
|
||||
cullFaceAttrib.cxx \
|
||||
cullHandler.cxx \
|
||||
cullPlanes.cxx \
|
||||
cullResult.cxx \
|
||||
cullTraverser.cxx \
|
||||
cullTraverserData.cxx \
|
||||
|
|
@ -229,6 +231,7 @@
|
|||
cullBinUnsorted.I cullBinUnsorted.h \
|
||||
cullFaceAttrib.I cullFaceAttrib.h \
|
||||
cullHandler.I cullHandler.h \
|
||||
cullPlanes.I cullPlanes.h \
|
||||
cullResult.I cullResult.h \
|
||||
cullTraverser.I cullTraverser.h \
|
||||
cullTraverserData.I cullTraverserData.h \
|
||||
|
|
|
|||
|
|
@ -516,6 +516,83 @@ filter_to_max(int max_clip_planes) const {
|
|||
return planeNode_attrib;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ClipPlaneAttrib::compose_off
|
||||
// Access: Public
|
||||
// Description: This is a special method which composes two
|
||||
// ClipPlaneAttribs with regard only to their set of
|
||||
// "off" clip planes, for the purposes of deriving
|
||||
// PandaNode::get_off_clip_planes().
|
||||
//
|
||||
// The result will be a ClipPlaneAttrib that represents
|
||||
// the union of all of the clip planes turned off in
|
||||
// either attrib. The set of on planes in the result is
|
||||
// undefined and should be ignored.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) ClipPlaneAttrib::
|
||||
compose_off(const RenderAttrib *other) const {
|
||||
const ClipPlaneAttrib *ta;
|
||||
DCAST_INTO_R(ta, other, 0);
|
||||
|
||||
if (_off_all_planes || (!ta->_off_all_planes && ta->_off_planes.empty())) {
|
||||
// If we turn off all planes, or the other turns none off, the
|
||||
// result is the same as this one.
|
||||
return this;
|
||||
}
|
||||
|
||||
if (ta->_off_all_planes || _off_planes.empty()) {
|
||||
// And contrariwise.
|
||||
return ta;
|
||||
}
|
||||
|
||||
Planes::const_iterator ai = _off_planes.begin();
|
||||
Planes::const_iterator bi = ta->_off_planes.begin();
|
||||
|
||||
// Create a new ClipPlaneAttrib that will hold the result.
|
||||
ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib;
|
||||
back_insert_iterator<Planes> result =
|
||||
back_inserter(new_attrib->_on_planes);
|
||||
|
||||
while (ai != _off_planes.end() &&
|
||||
bi != ta->_off_planes.end()) {
|
||||
if ((*ai) < (*bi)) {
|
||||
// Here is a plane that we have in the original, which is not
|
||||
// present in the secondary.
|
||||
*result = *ai;
|
||||
++ai;
|
||||
++result;
|
||||
|
||||
} else if ((*bi) < (*ai)) {
|
||||
// Here is a new plane we have in the secondary, that was not
|
||||
// present in the original.
|
||||
*result = *bi;
|
||||
++bi;
|
||||
++result;
|
||||
|
||||
} else { // (*bi) == (*ai)
|
||||
// Here is a plane we have in both.
|
||||
*result = *bi;
|
||||
++ai;
|
||||
++bi;
|
||||
++result;
|
||||
}
|
||||
}
|
||||
|
||||
while (ai != _off_planes.end()) {
|
||||
*result = *ai;
|
||||
++ai;
|
||||
++result;
|
||||
}
|
||||
|
||||
while (bi != ta->_off_planes.end()) {
|
||||
*result = *bi;
|
||||
++bi;
|
||||
++result;
|
||||
}
|
||||
|
||||
return return_new(new_attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ClipPlaneAttrib::issue
|
||||
// Access: Public, Virtual
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ PUBLISHED:
|
|||
CPT(ClipPlaneAttrib) filter_to_max(int max_clip_planes) const;
|
||||
|
||||
public:
|
||||
CPT(RenderAttrib) compose_off(const RenderAttrib *other) const;
|
||||
virtual void issue(GraphicsStateGuardianBase *gsg) const;
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
// Filename: cullPlanes.I
|
||||
// Created by: drose (23Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CullPlanes::
|
||||
CullPlanes() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::Copy Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CullPlanes::
|
||||
CullPlanes(const CullPlanes ©) :
|
||||
_planes(copy._planes)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::Copy Assignment Operator
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CullPlanes::
|
||||
operator = (const CullPlanes ©) {
|
||||
_planes = copy._planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CullPlanes::
|
||||
~CullPlanes() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::is_empty
|
||||
// Access: Public
|
||||
// Description: Returns true if there are no planes listed in the
|
||||
// CullPlanes object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool CullPlanes::
|
||||
is_empty() const {
|
||||
return _planes.empty();
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
// Filename: cullPlanes.cxx
|
||||
// Created by: drose (23Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cullPlanes.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::make_empty
|
||||
// Access: Public, Static
|
||||
// Description: Returns a pointer to an empty CullPlanes object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(CullPlanes) CullPlanes::
|
||||
make_empty() {
|
||||
static CPT(CullPlanes) empty;
|
||||
if (empty == NULL) {
|
||||
empty = new CullPlanes;
|
||||
// Artificially tick the reference count, just to ensure we won't
|
||||
// accidentally modify this object in any of the copy-on-write
|
||||
// operations below.
|
||||
empty->ref();
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::xform
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to a new CullPlanes object that is
|
||||
// the same as this one, but with the clip planes
|
||||
// modified by the indicated transform.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(CullPlanes) CullPlanes::
|
||||
xform(const LMatrix4f &mat) const {
|
||||
PT(CullPlanes) new_planes;
|
||||
if (get_ref_count() == 1) {
|
||||
new_planes = (CullPlanes *)this;
|
||||
} else {
|
||||
new_planes = new CullPlanes(*this);
|
||||
}
|
||||
|
||||
for (Planes::iterator pi = new_planes->_planes.begin();
|
||||
pi != new_planes->_planes.end();
|
||||
++pi) {
|
||||
if ((*pi).second->get_ref_count() != 1) {
|
||||
(*pi).second = DCAST(BoundingPlane, (*pi).second->make_copy());
|
||||
}
|
||||
(*pi).second->xform(mat);
|
||||
}
|
||||
|
||||
return new_planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::apply_state
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to a new CullPlanes object that is
|
||||
// the same as this one, but with the indicated
|
||||
// attributes applied to the state.
|
||||
//
|
||||
// In particular, any new ClipPlanes given in
|
||||
// net_attrib, if it is not NULL, will be added to the
|
||||
// state, unless those ClipPlanes are also listed in
|
||||
// off_attrib.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(CullPlanes) CullPlanes::
|
||||
apply_state(const CullTraverser *trav, const CullTraverserData *data,
|
||||
const ClipPlaneAttrib *net_attrib,
|
||||
const ClipPlaneAttrib *off_attrib) const {
|
||||
if (net_attrib == (ClipPlaneAttrib *)NULL) {
|
||||
return this;
|
||||
}
|
||||
|
||||
PT(CullPlanes) new_planes;
|
||||
if (get_ref_count() == 1) {
|
||||
new_planes = (CullPlanes *)this;
|
||||
} else {
|
||||
new_planes = new CullPlanes(*this);
|
||||
}
|
||||
|
||||
CPT(TransformState) net_transform = NULL;
|
||||
|
||||
int num_on_planes = net_attrib->get_num_on_planes();
|
||||
for (int i = 0; i < num_on_planes; ++i) {
|
||||
NodePath clip_plane = net_attrib->get_on_plane(i);
|
||||
Planes::const_iterator pi = new_planes->_planes.find(clip_plane);
|
||||
if (pi == new_planes->_planes.end()) {
|
||||
if (!off_attrib->has_off_plane(clip_plane)) {
|
||||
// Here's a new clip plane; add it to the list. For this we
|
||||
// need the net transform to this node.
|
||||
if (net_transform == (TransformState *)NULL) {
|
||||
net_transform = data->get_net_transform(trav);
|
||||
}
|
||||
|
||||
PlaneNode *plane_node = DCAST(PlaneNode, clip_plane.node());
|
||||
CPT(TransformState) new_transform =
|
||||
net_transform->invert_compose(clip_plane.get_net_transform());
|
||||
|
||||
Planef plane = plane_node->get_plane() * new_transform->get_mat();
|
||||
new_planes->_planes[clip_plane] = new BoundingPlane(-plane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new_planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::do_cull
|
||||
// Access: Public
|
||||
// Description: Tests the indicated bounding volume against all of
|
||||
// the clip planes in this object. Sets result to an
|
||||
// appropriate union of
|
||||
// BoundingVolume::IntersectionFlags, similar to the
|
||||
// result of BoundingVolume::contains().
|
||||
//
|
||||
// Also, if the bounding volume is completely in front
|
||||
// of any of the clip planes, removes those planes both
|
||||
// from this object and from the indicated state,
|
||||
// returning a new CullPlanes object in that case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(CullPlanes) CullPlanes::
|
||||
do_cull(int &result, CPT(RenderState) &state,
|
||||
const GeometricBoundingVolume *node_gbv) const {
|
||||
// We should have a ClipPlaneAttrib in the state if we've called
|
||||
// this method.
|
||||
CPT(ClipPlaneAttrib) orig_cpa = state->get_clip_plane();
|
||||
nassertr(orig_cpa != (ClipPlaneAttrib *)NULL, this);
|
||||
|
||||
result =
|
||||
BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
|
||||
|
||||
CPT(CullPlanes) new_planes = this;
|
||||
CPT(ClipPlaneAttrib) new_cpa = orig_cpa;
|
||||
|
||||
Planes::const_iterator pi;
|
||||
for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
|
||||
int plane_result = (*pi).second->contains(node_gbv);
|
||||
if (plane_result == BoundingVolume::IF_no_intersection) {
|
||||
// The node is completely behind this clip plane. Short-circuit
|
||||
// the rest of the logic; none of the other planes matter.
|
||||
result = plane_result;
|
||||
return new_planes;
|
||||
}
|
||||
|
||||
if ((plane_result & BoundingVolume::IF_all) != 0) {
|
||||
// The node is completely in front of this clip plane. We don't
|
||||
// need to consider this plane ever again for any descendents of
|
||||
// this node.
|
||||
new_planes = new_planes->remove_plane((*pi).first);
|
||||
nassertr(new_planes != this, new_planes);
|
||||
new_cpa = DCAST(ClipPlaneAttrib, new_cpa->remove_on_plane((*pi).first));
|
||||
}
|
||||
|
||||
result &= plane_result;
|
||||
}
|
||||
|
||||
if (new_cpa != orig_cpa) {
|
||||
if (new_cpa->is_identity()) {
|
||||
state = state->remove_attrib(ClipPlaneAttrib::get_class_type());
|
||||
} else {
|
||||
state = state->add_attrib(new_cpa);
|
||||
}
|
||||
}
|
||||
|
||||
return new_planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::remove_plane
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to a new CullPlanes object that is
|
||||
// the same as this one, but with the indicated
|
||||
// clip plane removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(CullPlanes) CullPlanes::
|
||||
remove_plane(const NodePath &clip_plane) const {
|
||||
PT(CullPlanes) new_planes;
|
||||
if (get_ref_count() == 1) {
|
||||
new_planes = (CullPlanes *)this;
|
||||
} else {
|
||||
new_planes = new CullPlanes(*this);
|
||||
}
|
||||
|
||||
Planes::iterator pi = new_planes->_planes.find(clip_plane);
|
||||
nassertr(pi != new_planes->_planes.end(), new_planes);
|
||||
new_planes->_planes.erase(pi);
|
||||
|
||||
return new_planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullPlanes::write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CullPlanes::
|
||||
write(ostream &out) const {
|
||||
out << "CullPlanes (" << _planes.size() << " planes):\n";
|
||||
Planes::const_iterator pi;
|
||||
for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
|
||||
out << " " << (*pi).first << " : " << *(*pi).second << "\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// Filename: cullPlanes.h
|
||||
// Created by: drose (23Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CULLPLANES_H
|
||||
#define CULLPLANES_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "referenceCount.h"
|
||||
#include "nodePath.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
#include "boundingPlane.h"
|
||||
#include "pointerTo.h"
|
||||
#include "luse.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CullPlanes
|
||||
// Description : This represents the set of clip planes that are
|
||||
// definitely in effect for the current node of the
|
||||
// CullTraverserData, as well as on all child nodes.
|
||||
// Any clip planes in this list may be safely culled
|
||||
// against.
|
||||
//
|
||||
// This does not include the clip planes that are in
|
||||
// effect now, but might later be turned off by a child
|
||||
// node, since we can't safely cull against such clip
|
||||
// planes.
|
||||
//
|
||||
// The bounding volumes in this object are transformed
|
||||
// for each level of the scene graph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA CullPlanes : public ReferenceCount {
|
||||
protected:
|
||||
INLINE CullPlanes();
|
||||
INLINE CullPlanes(const CullPlanes ©);
|
||||
INLINE void operator = (const CullPlanes ©);
|
||||
|
||||
public:
|
||||
INLINE ~CullPlanes();
|
||||
|
||||
INLINE bool is_empty() const;
|
||||
|
||||
static CPT(CullPlanes) make_empty();
|
||||
CPT(CullPlanes) xform(const LMatrix4f &mat) const;
|
||||
CPT(CullPlanes) apply_state(const CullTraverser *trav,
|
||||
const CullTraverserData *data,
|
||||
const ClipPlaneAttrib *net_attrib,
|
||||
const ClipPlaneAttrib *off_attrib) const;
|
||||
CPT(CullPlanes) do_cull(int &result, CPT(RenderState) &state,
|
||||
const GeometricBoundingVolume *node_gbv) const;
|
||||
|
||||
CPT(CullPlanes) remove_plane(const NodePath &clip_plane) const;
|
||||
|
||||
void write(ostream &out) const;
|
||||
|
||||
private:
|
||||
typedef pmap<NodePath, PT(BoundingPlane) > Planes;
|
||||
Planes _planes;
|
||||
};
|
||||
|
||||
#include "cullPlanes.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -166,8 +166,7 @@ traverse(CullTraverserData &data) {
|
|||
|
||||
data.apply_transform_and_state(this);
|
||||
|
||||
const RenderState *node_state = node->get_state();
|
||||
const FogAttrib *fog = node_state->get_fog();
|
||||
const FogAttrib *fog = node->get_state()->get_fog();
|
||||
if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
|
||||
// If we just introduced a FogAttrib here, call adjust_to_camera()
|
||||
// now. This maybe isn't the perfect time to call it, but it's
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ CullTraverserData(const NodePath &start,
|
|||
_modelview_transform(modelview_transform),
|
||||
_state(state),
|
||||
_view_frustum(view_frustum),
|
||||
_guard_band(guard_band)
|
||||
_guard_band(guard_band),
|
||||
_cull_planes(CullPlanes::make_empty())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +47,8 @@ CullTraverserData(const CullTraverserData ©) :
|
|||
_modelview_transform(copy._modelview_transform),
|
||||
_state(copy._state),
|
||||
_view_frustum(copy._view_frustum),
|
||||
_guard_band(copy._guard_band)
|
||||
_guard_band(copy._guard_band),
|
||||
_cull_planes(copy._cull_planes)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -62,6 +64,7 @@ operator = (const CullTraverserData ©) {
|
|||
_state = copy._state;
|
||||
_view_frustum = copy._view_frustum;
|
||||
_guard_band = copy._guard_band;
|
||||
_cull_planes = copy._cull_planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -76,7 +79,8 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) :
|
|||
_modelview_transform(parent._modelview_transform),
|
||||
_state(parent._state),
|
||||
_view_frustum(parent._view_frustum),
|
||||
_guard_band(parent._guard_band)
|
||||
_guard_band(parent._guard_band),
|
||||
_cull_planes(parent._cull_planes)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -132,9 +136,10 @@ is_in_view(const DrawMask &camera_mask) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (_view_frustum == (GeometricBoundingVolume *)NULL) {
|
||||
// If the transform is valid, but we don't have a frustum, it's
|
||||
// always in.
|
||||
if (_view_frustum == (GeometricBoundingVolume *)NULL &&
|
||||
_cull_planes->is_empty()) {
|
||||
// If the transform is valid, but we don't have a frustum or any
|
||||
// clip planes, it's always in.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -142,3 +147,28 @@ is_in_view(const DrawMask &camera_mask) {
|
|||
return is_in_view_impl();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullTraverserData::test_within_clip_planes
|
||||
// Access: Public
|
||||
// Description: Returns the BoundingVolume intersection bits
|
||||
// appropriate for the intersection of the current clip
|
||||
// planes with the current node.
|
||||
//
|
||||
// That is, if the current node is within all clip
|
||||
// planes (and will not be clipped at all), returns
|
||||
// BoundingVolume::IF_all. If it is completely behind
|
||||
// at least one clip plane, returns
|
||||
// BoundingVolume::IF_intersection. If it is partially
|
||||
// behind one or more clip planes, returns
|
||||
// BoundingVolume::IF_some.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int CullTraverserData::
|
||||
test_within_clip_planes(const CullTraverser *trav) const {
|
||||
const ClipPlaneAttrib *cpa = _state->get_clip_plane();
|
||||
if (cpa != (ClipPlaneAttrib *)NULL) {
|
||||
return test_within_clip_planes_impl(trav, cpa);
|
||||
}
|
||||
// No clip plane attrib; therefore, the node is not clipped at
|
||||
// all.
|
||||
return BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "colorAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "renderModeAttrib.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
#include "boundingPlane.h"
|
||||
#include "billboardEffect.h"
|
||||
#include "compassEffect.h"
|
||||
#include "polylightEffect.h"
|
||||
|
|
@ -62,7 +64,8 @@ apply_transform_and_state(CullTraverser *trav) {
|
|||
}
|
||||
|
||||
apply_transform_and_state(trav, node->get_transform(),
|
||||
node_state, node->get_effects());
|
||||
node_state, node->get_effects(),
|
||||
node->get_off_clip_planes());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -76,7 +79,8 @@ void CullTraverserData::
|
|||
apply_transform_and_state(CullTraverser *trav,
|
||||
CPT(TransformState) node_transform,
|
||||
CPT(RenderState) node_state,
|
||||
CPT(RenderEffects) node_effects) {
|
||||
CPT(RenderEffects) node_effects,
|
||||
const RenderAttrib *off_clip_planes) {
|
||||
if (node_effects->has_cull_callback()) {
|
||||
node_effects->cull_callback(trav, *this, node_transform, node_state);
|
||||
}
|
||||
|
|
@ -85,7 +89,8 @@ apply_transform_and_state(CullTraverser *trav,
|
|||
_modelview_transform = _modelview_transform->compose(node_transform);
|
||||
|
||||
if ((_view_frustum != (GeometricBoundingVolume *)NULL) ||
|
||||
(_guard_band != (GeometricBoundingVolume *)NULL)) {
|
||||
(_guard_band != (GeometricBoundingVolume *)NULL) ||
|
||||
(!_cull_planes->is_empty())) {
|
||||
// We need to move the viewing frustums into the node's
|
||||
// coordinate space by applying the node's inverse transform.
|
||||
if (node_transform->is_singular()) {
|
||||
|
|
@ -94,6 +99,7 @@ apply_transform_and_state(CullTraverser *trav,
|
|||
// point down.
|
||||
_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
_guard_band = (GeometricBoundingVolume *)NULL;
|
||||
_cull_planes = CullPlanes::make_empty();
|
||||
|
||||
} else {
|
||||
CPT(TransformState) inv_transform =
|
||||
|
|
@ -110,11 +116,16 @@ apply_transform_and_state(CullTraverser *trav,
|
|||
_guard_band = DCAST(GeometricBoundingVolume, _guard_band->make_copy());
|
||||
_guard_band->xform(inv_transform->get_mat());
|
||||
}
|
||||
|
||||
_cull_planes = _cull_planes->xform(inv_transform->get_mat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_state = _state->compose(node_state);
|
||||
_cull_planes = _cull_planes->apply_state(trav, this,
|
||||
_state->get_clip_plane(),
|
||||
DCAST(ClipPlaneAttrib, off_clip_planes));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -124,55 +135,131 @@ apply_transform_and_state(CullTraverser *trav,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool CullTraverserData::
|
||||
is_in_view_impl() {
|
||||
// By the time we get here, we know we have a viewing frustum.
|
||||
nassertr(_view_frustum != (GeometricBoundingVolume *)NULL, true);
|
||||
|
||||
const BoundingVolume &node_volume = node()->get_bound();
|
||||
nassertr(node_volume.is_of_type(GeometricBoundingVolume::get_class_type()), false);
|
||||
const GeometricBoundingVolume *node_gbv =
|
||||
DCAST(GeometricBoundingVolume, &node_volume);
|
||||
|
||||
int result = _view_frustum->contains(node_gbv);
|
||||
|
||||
if (pgraph_cat.is_spam()) {
|
||||
pgraph_cat.spam()
|
||||
<< _node_path << " cull result = " << hex << result << dec << "\n";
|
||||
}
|
||||
|
||||
if (result == BoundingVolume::IF_no_intersection) {
|
||||
// No intersection at all. Cull.
|
||||
if (!fake_view_frustum_cull) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have fake view-frustum culling enabled, instead of
|
||||
// actually culling an object we simply force it to be drawn in
|
||||
// red wireframe.
|
||||
_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
|
||||
_state = _state->compose(fake_state);
|
||||
if (_view_frustum != (GeometricBoundingVolume *)NULL) {
|
||||
int result = _view_frustum->contains(node_gbv);
|
||||
|
||||
} else if ((result & BoundingVolume::IF_all) != 0) {
|
||||
// The node and its descendants are completely enclosed within
|
||||
// the frustum. No need to cull further.
|
||||
_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
_guard_band = (GeometricBoundingVolume *)NULL;
|
||||
|
||||
} else {
|
||||
if (node()->is_final()) {
|
||||
// The bounding volume is partially, but not completely,
|
||||
// within the viewing frustum. Normally we'd keep testing
|
||||
// child bounding volumes as we continue down. But this node
|
||||
// has the "final" flag, so the user is claiming that there is
|
||||
// some important reason we should consider everything visible
|
||||
// at this point. So be it.
|
||||
if (pgraph_cat.is_spam()) {
|
||||
pgraph_cat.spam()
|
||||
<< _node_path << " cull result = " << hex << result << dec << "\n";
|
||||
}
|
||||
|
||||
if (result == BoundingVolume::IF_no_intersection) {
|
||||
// No intersection at all. Cull.
|
||||
if (!fake_view_frustum_cull) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have fake view-frustum culling enabled, instead of
|
||||
// actually culling an object we simply force it to be drawn in
|
||||
// red wireframe.
|
||||
_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
|
||||
_state = _state->compose(fake_state);
|
||||
|
||||
} else if ((result & BoundingVolume::IF_all) != 0) {
|
||||
// The node and its descendents are completely enclosed within
|
||||
// the frustum. No need to cull further.
|
||||
_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
_guard_band = (GeometricBoundingVolume *)NULL;
|
||||
|
||||
} else {
|
||||
// The node is partially, but not completely, within the viewing
|
||||
// frustum.
|
||||
if (node()->is_final()) {
|
||||
// Normally we'd keep testing child bounding volumes as we
|
||||
// continue down. But this node has the "final" flag, so the
|
||||
// user is claiming that there is some important reason we
|
||||
// should consider everything visible at this point. So be it.
|
||||
_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cull_planes->is_empty()) {
|
||||
// Also cull against the current clip planes.
|
||||
int result;
|
||||
_cull_planes = _cull_planes->do_cull(result, _state, node_gbv);
|
||||
|
||||
if (pgraph_cat.is_spam()) {
|
||||
pgraph_cat.spam()
|
||||
<< _node_path << " cull planes cull result = " << hex
|
||||
<< result << dec << "\n";
|
||||
_cull_planes->write(pgraph_cat.spam(false));
|
||||
}
|
||||
|
||||
if (result == BoundingVolume::IF_no_intersection) {
|
||||
// No intersection at all. Cull.
|
||||
return false;
|
||||
|
||||
} else if ((result & BoundingVolume::IF_all) != 0) {
|
||||
// The node and its descendents are completely in front of all
|
||||
// of the clip planes. The do_cull() call should therefore have
|
||||
// removed all of the clip planes.
|
||||
nassertr(_cull_planes->is_empty(), true);
|
||||
|
||||
} else {
|
||||
// The node is partially within one or more clip planes.
|
||||
if (node()->is_final()) {
|
||||
// Even though the node is only partially within the clip
|
||||
// planes, stop culling against them.
|
||||
_cull_planes = CullPlanes::make_empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullTraverserData::test_within_clip_planes_impl
|
||||
// Access: Private
|
||||
// Description: The private implementation of test_within_clip_planes().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CullTraverserData::
|
||||
test_within_clip_planes_impl(const CullTraverser *trav,
|
||||
const ClipPlaneAttrib *cpa) const {
|
||||
int result = BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
|
||||
|
||||
|
||||
const BoundingVolume &node_volume = node()->get_bound();
|
||||
nassertr(node_volume.is_of_type(GeometricBoundingVolume::get_class_type()), result);
|
||||
const GeometricBoundingVolume *node_gbv =
|
||||
DCAST(GeometricBoundingVolume, &node_volume);
|
||||
|
||||
CPT(TransformState) net_transform = get_net_transform(trav);
|
||||
|
||||
cerr << "considering " << _node_path << ", bv = " << *node_gbv << "\n";
|
||||
cerr << " net_transform = " << *net_transform << "\n";
|
||||
|
||||
int num_planes = cpa->get_num_on_planes();
|
||||
for (int i = 0;
|
||||
i < num_planes && result != BoundingVolume::IF_no_intersection;
|
||||
++i) {
|
||||
NodePath plane_path = cpa->get_on_plane(i);
|
||||
PlaneNode *plane_node = DCAST(PlaneNode, plane_path.node());
|
||||
CPT(TransformState) new_transform =
|
||||
net_transform->invert_compose(plane_path.get_net_transform());
|
||||
|
||||
Planef plane = plane_node->get_plane() * new_transform->get_mat();
|
||||
BoundingPlane bplane(-plane);
|
||||
cerr << " " << bplane << " -> " << bplane.contains(node_gbv) << "\n";
|
||||
result &= bplane.contains(node_gbv);
|
||||
}
|
||||
|
||||
if (pgraph_cat.is_spam()) {
|
||||
pgraph_cat.spam()
|
||||
<< _node_path << " test_within_clip_planes result = "
|
||||
<< hex << result << dec << "\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullTraverserData::get_fake_view_frustum_cull_state
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#define CULLTRAVERSERDATA_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "cullPlanes.h"
|
||||
#include "workingNodePath.h"
|
||||
#include "renderState.h"
|
||||
#include "transformState.h"
|
||||
|
|
@ -64,20 +64,27 @@ public:
|
|||
CPT(TransformState) get_net_transform(const CullTraverser *trav) const;
|
||||
|
||||
INLINE bool is_in_view(const DrawMask &camera_mask);
|
||||
INLINE int test_within_clip_planes(const CullTraverser *trav) const;
|
||||
|
||||
void apply_transform_and_state(CullTraverser *trav);
|
||||
void apply_transform_and_state(CullTraverser *trav,
|
||||
CPT(TransformState) node_transform,
|
||||
CPT(RenderState) node_state,
|
||||
CPT(RenderEffects) node_effects);
|
||||
CPT(RenderEffects) node_effects,
|
||||
const RenderAttrib *off_clip_planes);
|
||||
|
||||
WorkingNodePath _node_path;
|
||||
CPT(TransformState) _modelview_transform;
|
||||
CPT(RenderState) _state;
|
||||
PT(GeometricBoundingVolume) _view_frustum;
|
||||
PT(GeometricBoundingVolume) _guard_band;
|
||||
CPT(CullPlanes) _cull_planes;
|
||||
|
||||
private:
|
||||
bool is_in_view_impl();
|
||||
int test_within_clip_planes_impl(const CullTraverser *trav,
|
||||
const ClipPlaneAttrib *cpa) const;
|
||||
|
||||
static CPT(RenderState) get_fake_view_frustum_cull_state();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ ModelNode(const string &name) :
|
|||
PandaNode(name)
|
||||
{
|
||||
_preserve_transform = PT_none;
|
||||
_preserve_attributes = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -66,6 +67,33 @@ get_preserve_transform() const {
|
|||
return _preserve_transform;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ModelNode::set_preserve_attributes
|
||||
// Access: Public
|
||||
// Description: Sets the preserve_attributes flag. This restricts the
|
||||
// ability of a flatten operation to affect the
|
||||
// render attributes stored on this node.
|
||||
//
|
||||
// The value should be the union of bits from
|
||||
// SceneGraphReducer::AttribTypes that represent the
|
||||
// attributes that should *not* be changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ModelNode::
|
||||
set_preserve_attributes(int preserve_attributes) {
|
||||
_preserve_attributes = preserve_attributes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ModelNode::get_preserve_attributes
|
||||
// Access: Public
|
||||
// Description: Returns the current setting of the preserve_attributes
|
||||
// flag. See set_preserve_attributes().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int ModelNode::
|
||||
get_preserve_attributes() const {
|
||||
return _preserve_attributes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ModelNode::Copy Constructor
|
||||
// Access: Protected
|
||||
|
|
@ -74,6 +102,7 @@ get_preserve_transform() const {
|
|||
INLINE ModelNode::
|
||||
ModelNode(const ModelNode ©) :
|
||||
PandaNode(copy),
|
||||
_preserve_transform(copy._preserve_transform)
|
||||
_preserve_transform(copy._preserve_transform),
|
||||
_preserve_attributes(copy._preserve_attributes)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,22 @@ preserve_name() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ModelNode::get_unsafe_to_apply_attribs
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the union of all attributes from
|
||||
// SceneGraphReducer::AttribTypes that may not safely be
|
||||
// applied to the vertices of this node. If this is
|
||||
// nonzero, these attributes must be dropped at this
|
||||
// node as a state change.
|
||||
//
|
||||
// This is a generalization of safe_to_transform().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int ModelNode::
|
||||
get_unsafe_to_apply_attribs() const {
|
||||
return _preserve_attributes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ModelNode::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
@ -130,6 +146,7 @@ void ModelNode::
|
|||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
PandaNode::write_datagram(manager, dg);
|
||||
dg.add_uint8((int)_preserve_transform);
|
||||
dg.add_uint16(_preserve_attributes);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -164,4 +181,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||
PandaNode::fillin(scan, manager);
|
||||
|
||||
_preserve_transform = (PreserveTransform)scan.get_uint8();
|
||||
_preserve_attributes = 0;
|
||||
if (manager->get_file_minor_ver() >= 3) {
|
||||
_preserve_attributes = scan.get_uint16();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ public:
|
|||
virtual bool safe_to_modify_transform() const;
|
||||
virtual bool safe_to_combine() const;
|
||||
virtual bool preserve_name() const;
|
||||
virtual int get_unsafe_to_apply_attribs() const;
|
||||
|
||||
PUBLISHED:
|
||||
enum PreserveTransform {
|
||||
|
|
@ -61,8 +62,12 @@ PUBLISHED:
|
|||
INLINE void set_preserve_transform(PreserveTransform preserve_transform);
|
||||
INLINE PreserveTransform get_preserve_transform() const;
|
||||
|
||||
INLINE void set_preserve_attributes(int attrib_mask);
|
||||
INLINE int get_preserve_attributes() const;
|
||||
|
||||
private:
|
||||
PreserveTransform _preserve_transform;
|
||||
int _preserve_attributes;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
|
|
|
|||
|
|
@ -436,7 +436,15 @@ get_stashed_sort(int n) const {
|
|||
INLINE void PandaNode::
|
||||
set_attrib(const RenderAttrib *attrib, int override) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = cdata->_state->add_attrib(attrib, override);
|
||||
CPT(RenderState) new_state = cdata->_state->add_attrib(attrib, override);
|
||||
if (cdata->_state != new_state) {
|
||||
cdata->_state = new_state;
|
||||
|
||||
// We mark the bound stale when the state changes, in case we have
|
||||
// changed a ClipPlaneAttrib.
|
||||
mark_bound_stale();
|
||||
state_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -483,7 +491,15 @@ has_attrib(TypeHandle type) const {
|
|||
INLINE void PandaNode::
|
||||
clear_attrib(TypeHandle type) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = cdata->_state->remove_attrib(type);
|
||||
CPT(RenderState) new_state = cdata->_state->remove_attrib(type);
|
||||
if (cdata->_state != new_state) {
|
||||
cdata->_state = new_state;
|
||||
|
||||
// We mark the bound stale when the state changes, in case we have
|
||||
// changed a ClipPlaneAttrib.
|
||||
mark_bound_stale();
|
||||
state_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -554,7 +570,14 @@ clear_effect(TypeHandle type) {
|
|||
INLINE void PandaNode::
|
||||
set_state(const RenderState *state) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = state;
|
||||
if (cdata->_state != state) {
|
||||
cdata->_state = state;
|
||||
|
||||
// We mark the bound stale when the state changes, in case we have
|
||||
// changed a ClipPlaneAttrib.
|
||||
mark_bound_stale();
|
||||
state_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -583,7 +606,14 @@ get_state() const {
|
|||
INLINE void PandaNode::
|
||||
clear_state() {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_state = RenderState::make_empty();
|
||||
if (!cdata->_state->is_empty()) {
|
||||
cdata->_state = RenderState::make_empty();
|
||||
|
||||
// We mark the bound stale when the state changes, in case we have
|
||||
// changed a ClipPlaneAttrib.
|
||||
mark_bound_stale();
|
||||
state_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -633,9 +663,11 @@ clear_effects() {
|
|||
INLINE void PandaNode::
|
||||
set_transform(const TransformState *transform) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_transform = transform;
|
||||
mark_bound_stale();
|
||||
transform_changed();
|
||||
if (cdata->_transform != transform) {
|
||||
cdata->_transform = transform;
|
||||
mark_bound_stale();
|
||||
transform_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -661,9 +693,11 @@ get_transform() const {
|
|||
INLINE void PandaNode::
|
||||
clear_transform() {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_transform = TransformState::make_identity();
|
||||
mark_bound_stale();
|
||||
transform_changed();
|
||||
if (!cdata->_transform->is_identity()) {
|
||||
cdata->_transform = TransformState::make_identity();
|
||||
mark_bound_stale();
|
||||
transform_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -819,7 +853,10 @@ ls(ostream &out, int indent_level) const {
|
|||
INLINE void PandaNode::
|
||||
set_draw_mask(DrawMask mask) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_draw_mask = mask;
|
||||
if (cdata->_draw_mask != mask) {
|
||||
cdata->_draw_mask = mask;
|
||||
draw_mask_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -887,6 +924,21 @@ get_net_collide_mask() const {
|
|||
return cdata->_net_collide_mask;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_off_clip_planes
|
||||
// Access: Published
|
||||
// Description: Returns a ClipPlaneAttrib which represents the union
|
||||
// of all of the clip planes that have been turned *off*
|
||||
// at this level and below.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const RenderAttrib *PandaNode::
|
||||
get_off_clip_planes() const {
|
||||
// Call get_bound() first to ensure the attrib is recomputed.
|
||||
BoundedObject::get_bound();
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_off_clip_planes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::set_bound
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "geometricBoundingVolume.h"
|
||||
#include "sceneGraphReducer.h"
|
||||
#include "accumulatedAttribs.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
|
||||
|
||||
TypeHandle PandaNode::_type_handle;
|
||||
|
|
@ -1581,6 +1582,12 @@ recompute_bound() {
|
|||
CDWriter cdata(_cycler);
|
||||
cdata->_net_collide_mask = cdata->_into_collide_mask;
|
||||
|
||||
// And compute the set of "off" clip planes.
|
||||
cdata->_off_clip_planes = cdata->_state->get_clip_plane();
|
||||
if (cdata->_off_clip_planes == (RenderAttrib *)NULL) {
|
||||
cdata->_off_clip_planes = ClipPlaneAttrib::make();
|
||||
}
|
||||
|
||||
// Now actually compute the bounding volume by putting it around all
|
||||
// of our child bounding volumes.
|
||||
pvector<const BoundingVolume *> child_volumes;
|
||||
|
|
@ -1595,6 +1602,8 @@ recompute_bound() {
|
|||
const BoundingVolume &child_bound = child->get_bound();
|
||||
child_volumes.push_back(&child_bound);
|
||||
cdata->_net_collide_mask |= child->get_net_collide_mask();
|
||||
CPT(ClipPlaneAttrib) orig = DCAST(ClipPlaneAttrib, cdata->_off_clip_planes);
|
||||
cdata->_off_clip_planes = orig->compose_off(child->get_off_clip_planes());
|
||||
}
|
||||
|
||||
const BoundingVolume **child_begin = &child_volumes[0];
|
||||
|
|
@ -1678,6 +1687,28 @@ void PandaNode::
|
|||
transform_changed() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::state_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called after the node's RenderState has been changed
|
||||
// for any reason, this just provides a hook so derived
|
||||
// classes can do something special in this case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
state_changed() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::draw_mask_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called after the node's DrawMask has been changed
|
||||
// for any reason, this just provides a hook so derived
|
||||
// classes can do something special in this case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PandaNode::
|
||||
draw_mask_changed() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::r_copy_subgraph
|
||||
// Access: Protected, Virtual
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ PUBLISHED:
|
|||
virtual CollideMask get_legal_collide_mask() const;
|
||||
|
||||
INLINE CollideMask get_net_collide_mask() const;
|
||||
INLINE const RenderAttrib *get_off_clip_planes() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
|
@ -225,6 +226,8 @@ protected:
|
|||
virtual void parents_changed();
|
||||
virtual void children_changed();
|
||||
virtual void transform_changed();
|
||||
virtual void state_changed();
|
||||
virtual void draw_mask_changed();
|
||||
INLINE void add_net_collide_mask(CollideMask mask);
|
||||
|
||||
typedef pmap<PandaNode *, PandaNode *> InstanceMap;
|
||||
|
|
@ -363,6 +366,13 @@ private:
|
|||
// we update them together.
|
||||
CollideMask _net_collide_mask;
|
||||
|
||||
// This is a ClipPlaneAttrib that represents the union of all clip
|
||||
// planes that have been turned *off* at and below this level. As
|
||||
// above, it's similar to a bounding volume, and is updated at the
|
||||
// same time. TODO: fix the circular reference counts involved
|
||||
// here.
|
||||
CPT(RenderAttrib) _off_clip_planes;
|
||||
|
||||
bool _fixed_internal_bound;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "cullBinUnsorted.cxx"
|
||||
#include "cullFaceAttrib.cxx"
|
||||
#include "cullHandler.cxx"
|
||||
#include "cullPlanes.cxx"
|
||||
#include "cullResult.cxx"
|
||||
#include "cullTraverser.cxx"
|
||||
#include "cullTraverserData.cxx"
|
||||
|
|
|
|||
|
|
@ -66,10 +66,11 @@ fillin(DatagramIterator &scan, BamReader *) {
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PlaneNode::
|
||||
PlaneNode(const string &name) :
|
||||
PlaneNode(const string &name, const Planef &plane) :
|
||||
PandaNode(name),
|
||||
_priority(0)
|
||||
{
|
||||
set_plane(plane);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PlaneNode : public PandaNode {
|
||||
PUBLISHED:
|
||||
PlaneNode(const string &name);
|
||||
PlaneNode(const string &name, const Planef &plane = Planef());
|
||||
|
||||
protected:
|
||||
PlaneNode(const PlaneNode ©);
|
||||
|
|
|
|||
|
|
@ -336,6 +336,25 @@ get_render_mode() const {
|
|||
return _render_mode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::get_clip_plane
|
||||
// Access: Published
|
||||
// Description: This function is provided as an optimization, to
|
||||
// speed up the render-time checking for the existance
|
||||
// of a ClipPlaneAttrib on this state. It returns a
|
||||
// pointer to the ClipPlaneAttrib, if there is one, or
|
||||
// NULL if there is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const ClipPlaneAttrib *RenderState::
|
||||
get_clip_plane() const {
|
||||
if ((_flags & F_checked_clip_plane) == 0) {
|
||||
// We pretend this function is const, even though it transparently
|
||||
// modifies the internal clip_plane cache.
|
||||
((RenderState *)this)->determine_clip_plane();
|
||||
}
|
||||
return _clip_plane;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::set_destructing
|
||||
// Access: Private
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "cullBinAttrib.h"
|
||||
#include "cullBinManager.h"
|
||||
#include "fogAttrib.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "colorScaleAttrib.h"
|
||||
|
|
@ -1647,6 +1648,21 @@ determine_render_mode() {
|
|||
_flags |= F_checked_render_mode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::determine_clip_plane
|
||||
// Access: Private
|
||||
// Description: This is the private implementation of get_clip_plane().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
determine_clip_plane() {
|
||||
const RenderAttrib *attrib = get_attrib(ClipPlaneAttrib::get_class_type());
|
||||
_clip_plane = (const ClipPlaneAttrib *)NULL;
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
_clip_plane = DCAST(ClipPlaneAttrib, attrib);
|
||||
}
|
||||
_flags |= F_checked_clip_plane;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::update_pstats
|
||||
// Access: Private
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ColorAttrib;
|
|||
class ColorScaleAttrib;
|
||||
class TextureAttrib;
|
||||
class TexGenAttrib;
|
||||
class ClipPlaneAttrib;
|
||||
class FactoryParams;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -133,6 +134,7 @@ PUBLISHED:
|
|||
INLINE const TexGenAttrib *get_tex_gen() const;
|
||||
INLINE const TexMatrixAttrib *get_tex_matrix() const;
|
||||
INLINE const RenderModeAttrib *get_render_mode() const;
|
||||
INLINE const ClipPlaneAttrib *get_clip_plane() const;
|
||||
|
||||
int get_geom_rendering(int geom_rendering) const;
|
||||
|
||||
|
|
@ -177,6 +179,7 @@ private:
|
|||
void determine_tex_gen();
|
||||
void determine_tex_matrix();
|
||||
void determine_render_mode();
|
||||
void determine_clip_plane();
|
||||
|
||||
INLINE void set_destructing();
|
||||
INLINE bool is_destructing() const;
|
||||
|
|
@ -274,6 +277,7 @@ private:
|
|||
const TexGenAttrib *_tex_gen;
|
||||
const TexMatrixAttrib *_tex_matrix;
|
||||
const RenderModeAttrib *_render_mode;
|
||||
const ClipPlaneAttrib *_clip_plane;
|
||||
|
||||
enum Flags {
|
||||
F_checked_bin_index = 0x0001,
|
||||
|
|
@ -286,6 +290,7 @@ private:
|
|||
F_checked_tex_gen = 0x0080,
|
||||
F_checked_tex_matrix = 0x0100,
|
||||
F_checked_render_mode = 0x0200,
|
||||
F_checked_clip_plane = 0x0400,
|
||||
F_is_destructing = 0x8000,
|
||||
};
|
||||
unsigned short _flags;
|
||||
|
|
|
|||
|
|
@ -12,49 +12,61 @@
|
|||
#define SOURCES \
|
||||
config_pgui.h \
|
||||
pgButton.I pgButton.h \
|
||||
pgSliderButton.I pgSliderButton.h \
|
||||
pgButtonNotify.I pgButtonNotify.h \
|
||||
pgCullTraverser.I pgCullTraverser.h \
|
||||
pgEntry.I pgEntry.h \
|
||||
pgMouseWatcherGroup.I pgMouseWatcherGroup.h \
|
||||
pgMouseWatcherParameter.I pgMouseWatcherParameter.h \
|
||||
pgFrameStyle.I pgFrameStyle.h \
|
||||
pgItem.I pgItem.h \
|
||||
pgItemNotify.I pgItemNotify.h \
|
||||
pgMouseWatcherBackground.h \
|
||||
pgMouseWatcherRegion.I pgMouseWatcherRegion.h \
|
||||
pgScrollFrame.I pgScrollFrame.h \
|
||||
pgSliderBar.I pgSliderBar.h \
|
||||
pgSliderBarNotify.I pgSliderBarNotify.h \
|
||||
pgTop.I pgTop.h \
|
||||
pgWaitBar.I pgWaitBar.h \
|
||||
pgSliderBar.I pgSliderBar.h
|
||||
pgVirtualFrame.I pgVirtualFrame.h \
|
||||
pgWaitBar.I pgWaitBar.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
config_pgui.cxx \
|
||||
pgButton.cxx \
|
||||
pgSliderButton.cxx \
|
||||
pgButtonNotify.cxx \
|
||||
pgCullTraverser.cxx \
|
||||
pgEntry.cxx \
|
||||
pgMouseWatcherGroup.cxx \
|
||||
pgMouseWatcherParameter.cxx \
|
||||
pgFrameStyle.cxx \
|
||||
pgItem.cxx \
|
||||
pgItemNotify.cxx \
|
||||
pgMouseWatcherBackground.cxx \
|
||||
pgMouseWatcherRegion.cxx \
|
||||
pgScrollFrame.cxx \
|
||||
pgSliderBar.cxx \
|
||||
pgSliderBarNotify.cxx \
|
||||
pgTop.cxx \
|
||||
pgWaitBar.cxx \
|
||||
pgSliderBar.cxx
|
||||
pgVirtualFrame.cxx \
|
||||
pgWaitBar.cxx
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
pgButton.I pgButton.h \
|
||||
pgSliderButton.I pgSliderButton.h \
|
||||
pgButtonNotify.I pgButtonNotify.h \
|
||||
pgCullTraverser.I pgCullTraverser.h \
|
||||
pgEntry.I pgEntry.h \
|
||||
pgMouseWatcherGroup.I pgMouseWatcherGroup.h \
|
||||
pgMouseWatcherParameter.I pgMouseWatcherParameter.h \
|
||||
pgFrameStyle.I pgFrameStyle.h \
|
||||
pgItem.I pgItem.h \
|
||||
pgItemNotify.I pgItemNotify.h \
|
||||
pgMouseWatcherBackground.h \
|
||||
pgMouseWatcherRegion.I pgMouseWatcherRegion.h \
|
||||
pgScrollFrame.I pgScrollFrame.h \
|
||||
pgSliderBar.I pgSliderBar.h \
|
||||
pgSliderBarNotify.I pgSliderBarNotify.h \
|
||||
pgTop.I pgTop.h \
|
||||
pgWaitBar.I pgWaitBar.h \
|
||||
pgSliderBar.I pgSliderBar.h
|
||||
pgVirtualFrame.I pgVirtualFrame.h \
|
||||
pgWaitBar.I pgWaitBar.h
|
||||
|
||||
|
||||
#define IGATESCAN all
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include "config_pgui.h"
|
||||
#include "pgButton.h"
|
||||
#include "pgSliderButton.h"
|
||||
#include "pgCullTraverser.h"
|
||||
#include "pgEntry.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
|
|
@ -26,9 +25,11 @@
|
|||
#include "pgItem.h"
|
||||
#include "pgMouseWatcherBackground.h"
|
||||
#include "pgMouseWatcherRegion.h"
|
||||
#include "pgTop.h"
|
||||
#include "pgWaitBar.h"
|
||||
#include "pgScrollFrame.h"
|
||||
#include "pgSliderBar.h"
|
||||
#include "pgTop.h"
|
||||
#include "pgVirtualFrame.h"
|
||||
#include "pgWaitBar.h"
|
||||
|
||||
#include "dconfig.h"
|
||||
|
||||
|
|
@ -39,6 +40,18 @@ ConfigureFn(config_pgui) {
|
|||
init_libpgui();
|
||||
}
|
||||
|
||||
ConfigVariableDouble scroll_initial_delay
|
||||
("scroll-initial-delay", 0.3,
|
||||
PRC_DESC("This is the amount of time, in seconds, to delay after the user "
|
||||
"first clicks and holds on a scrollbar button before the scrolling "
|
||||
"continues automatically."));
|
||||
|
||||
ConfigVariableDouble scroll_continued_delay
|
||||
("scroll-continued-delay", 0.1,
|
||||
PRC_DESC("This is the amount of time, in seconds, to delay between lines "
|
||||
"scrolled while the user is continuing to hold down the scrollbar "
|
||||
"button."));
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libpgui
|
||||
// Description: Initializes the library. This must be called at
|
||||
|
|
@ -56,7 +69,6 @@ init_libpgui() {
|
|||
initialized = true;
|
||||
|
||||
PGButton::init_type();
|
||||
PGSliderButton::init_type();
|
||||
PGCullTraverser::init_type();
|
||||
PGEntry::init_type();
|
||||
PGMouseWatcherParameter::init_type();
|
||||
|
|
@ -64,7 +76,9 @@ init_libpgui() {
|
|||
PGItem::init_type();
|
||||
PGMouseWatcherBackground::init_type();
|
||||
PGMouseWatcherRegion::init_type();
|
||||
PGTop::init_type();
|
||||
PGWaitBar::init_type();
|
||||
PGScrollFrame::init_type();
|
||||
PGSliderBar::init_type();
|
||||
PGTop::init_type();
|
||||
PGVirtualFrame::init_type();
|
||||
PGWaitBar::init_type();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,13 @@
|
|||
|
||||
#include "pandabase.h"
|
||||
#include "notifyCategoryProxy.h"
|
||||
#include "configVariableDouble.h"
|
||||
|
||||
NotifyCategoryDecl(pgui, EXPCL_PANDA, EXPTP_PANDA);
|
||||
|
||||
// Configure variables for pgui package.
|
||||
extern ConfigVariableDouble scroll_initial_delay;
|
||||
extern ConfigVariableDouble scroll_continued_delay;
|
||||
|
||||
extern EXPCL_PANDA void init_libpgui();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,32 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGButton::set_notify
|
||||
// Access: Published
|
||||
// Description: Sets the object which will be notified when the
|
||||
// PGButton changes. Set this to NULL to disable
|
||||
// this effect. The PGButton does not retain
|
||||
// ownership of the pointer; it is your responsibility
|
||||
// to ensure that the notify object does not destruct.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGButton::
|
||||
set_notify(PGButtonNotify *notify) {
|
||||
PGItem::set_notify(notify);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGButton::get_notify
|
||||
// Access: Published
|
||||
// Description: Returns the object which will be notified when the
|
||||
// PGButton changes, if any. Returns NULL if there
|
||||
// is no such object configured.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGButtonNotify *PGButton::
|
||||
get_notify() const {
|
||||
return (PGButtonNotify *)PGItem::get_notify();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGButton::setup
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -156,18 +156,10 @@ click(const MouseWatcherParameter ¶m) {
|
|||
string event = get_click_event(param.get_button());
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGButton::move
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse is moved while the mouse
|
||||
// is within the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
move(const MouseWatcherParameter ¶m) {
|
||||
PGItem::move(param);
|
||||
if (has_notify()) {
|
||||
get_notify()->button_click(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -180,7 +172,7 @@ move(const MouseWatcherParameter ¶m) {
|
|||
// according to the size of the text.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGButton::
|
||||
setup(const string &label) {
|
||||
setup(const string &label, float bevel) {
|
||||
clear_state_def(S_ready);
|
||||
clear_state_def(S_depressed);
|
||||
clear_state_def(S_rollover);
|
||||
|
|
@ -200,7 +192,7 @@ setup(const string &label) {
|
|||
|
||||
PGFrameStyle style;
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
style.set_width(0.1f, 0.1f);
|
||||
style.set_width(bevel, bevel);
|
||||
|
||||
style.set_type(PGFrameStyle::T_bevel_out);
|
||||
set_frame_style(S_ready, style);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "pandabase.h"
|
||||
|
||||
#include "pgItem.h"
|
||||
#include "pgButtonNotify.h"
|
||||
#include "nodePath.h"
|
||||
#include "pset.h"
|
||||
|
||||
|
|
@ -37,6 +38,9 @@ PUBLISHED:
|
|||
PGButton(const string &name);
|
||||
virtual ~PGButton();
|
||||
|
||||
protected:
|
||||
PGButton(const PGButton ©);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
|
||||
|
|
@ -46,10 +50,9 @@ public:
|
|||
virtual void release(const MouseWatcherParameter ¶m, bool background);
|
||||
|
||||
virtual void click(const MouseWatcherParameter ¶m);
|
||||
|
||||
virtual void move(const MouseWatcherParameter ¶m);
|
||||
|
||||
PGButton(const PGButton ©);
|
||||
INLINE void set_notify(PGButtonNotify *notify);
|
||||
INLINE PGButtonNotify *get_notify() const;
|
||||
|
||||
PUBLISHED:
|
||||
enum State {
|
||||
|
|
@ -59,7 +62,7 @@ PUBLISHED:
|
|||
S_inactive
|
||||
};
|
||||
|
||||
void setup(const string &label);
|
||||
void setup(const string &label, float bevel = 0.1f);
|
||||
INLINE void setup(const NodePath &ready);
|
||||
INLINE void setup(const NodePath &ready, const NodePath &depressed);
|
||||
INLINE void setup(const NodePath &ready, const NodePath &depressed,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Filename: pgButtonNotify.I
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGButtonNotify::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGButtonNotify::
|
||||
PGButtonNotify() {
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Filename: pgButtonNotify.cxx
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgButtonNotify.h"
|
||||
#include "pgButton.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGButtonNotify::button_click
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGButton has been clicked.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGButtonNotify::
|
||||
button_click(PGButton *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Filename: pgButtonNotify.h
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGBUTTONNOTIFY_H
|
||||
#define PGBUTTONNOTIFY_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pgItemNotify.h"
|
||||
|
||||
class PGButton;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGButtonNotify
|
||||
// Description : Objects that inherit from this class can receive
|
||||
// notify messages when a slider bar moves or otherwise
|
||||
// is reconfigured.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGButtonNotify : public PGItemNotify {
|
||||
public:
|
||||
INLINE PGButtonNotify();
|
||||
|
||||
protected:
|
||||
virtual void button_click(PGButton *button, const MouseWatcherParameter ¶m);
|
||||
|
||||
friend class PGButton;
|
||||
};
|
||||
|
||||
#include "pgButtonNotify.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@ PGFrameStyle() {
|
|||
_type = T_none;
|
||||
_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
_width.set(0.1f, 0.1f);
|
||||
_visible_scale.set(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -39,7 +40,8 @@ PGFrameStyle(const PGFrameStyle ©) :
|
|||
_type(copy._type),
|
||||
_color(copy._color),
|
||||
_texture(copy._texture),
|
||||
_width(copy._width)
|
||||
_width(copy._width),
|
||||
_visible_scale(copy._visible_scale)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +56,7 @@ operator = (const PGFrameStyle ©) {
|
|||
_color = copy._color;
|
||||
_texture = copy._texture;
|
||||
_width = copy._width;
|
||||
_visible_scale = copy._visible_scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -197,6 +200,48 @@ get_width() const {
|
|||
return _width;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGFrameStyle::set_visible_scale
|
||||
// Access: Published
|
||||
// Description: Sets a scale factor on the visible representation of
|
||||
// the frame, in the X and Y directions. If this scale
|
||||
// factor is other than 1, it will affect the size of
|
||||
// the visible frame representation within the actual
|
||||
// frame border.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGFrameStyle::
|
||||
set_visible_scale(float x, float y) {
|
||||
set_visible_scale(LVecBase2f(x, y));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGFrameStyle::set_visible_scale
|
||||
// Access: Published
|
||||
// Description: Sets a scale factor on the visible representation of
|
||||
// the frame, in the X and Y directions. If this scale
|
||||
// factor is other than 1, it will affect the size of
|
||||
// the visible frame representation within the actual
|
||||
// frame border.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGFrameStyle::
|
||||
set_visible_scale(const LVecBase2f &visible_scale) {
|
||||
_visible_scale = visible_scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGFrameStyle::get_visible_scale
|
||||
// Access: Published
|
||||
// Description: Returns the scale factor on the visible
|
||||
// representation of the frame, in the X and Y
|
||||
// directions. If this scale factor is other than 1, it
|
||||
// will affect the size of the visible frame
|
||||
// representation within the actual frame border.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase2f &PGFrameStyle::
|
||||
get_visible_scale() const {
|
||||
return _visible_scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGFrameStyle ostream output
|
||||
// Description:
|
||||
|
|
|
|||
|
|
@ -60,6 +60,39 @@ operator << (ostream &out, PGFrameStyle::Type type) {
|
|||
return out << "**unknown(" << (int)type << ")**";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGFrameStyle::get_internal_frame
|
||||
// Access: Published
|
||||
// Description: Computes the size of the internal frame, given the
|
||||
// indicated external frame, appropriate for this kind
|
||||
// of frame style. This simply subtracts the border
|
||||
// width for those frame styles that include a border.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LVecBase4f PGFrameStyle::
|
||||
get_internal_frame(const LVecBase4f &frame) const {
|
||||
LPoint2f center((frame[0] + frame[1]) / 2.0f,
|
||||
(frame[2] + frame[3]) / 2.0f);
|
||||
LVecBase4f scaled_frame
|
||||
((frame[0] - center[0]) * _visible_scale[0] + center[0],
|
||||
(frame[1] - center[0]) * _visible_scale[0] + center[0],
|
||||
(frame[2] - center[1]) * _visible_scale[1] + center[1],
|
||||
(frame[3] - center[1]) * _visible_scale[1] + center[1]);
|
||||
|
||||
switch (_type) {
|
||||
case T_none:
|
||||
case T_flat:
|
||||
return scaled_frame;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return LVecBase4f(scaled_frame[0] + _width[0],
|
||||
scaled_frame[1] - _width[0],
|
||||
scaled_frame[2] + _width[1],
|
||||
scaled_frame[3] - _width[1]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGFrameStyle::output
|
||||
// Access: Published
|
||||
|
|
@ -68,6 +101,9 @@ operator << (ostream &out, PGFrameStyle::Type type) {
|
|||
void PGFrameStyle::
|
||||
output(ostream &out) const {
|
||||
out << _type << " color = " << _color << " width = " << _width;
|
||||
if (_visible_scale != LVecBase2f(1.0f, 1.0f)) {
|
||||
out << "visible_scale = " << get_visible_scale();
|
||||
}
|
||||
if (has_texture()) {
|
||||
out << " texture = " << *get_texture();
|
||||
}
|
||||
|
|
@ -126,28 +162,36 @@ NodePath PGFrameStyle::
|
|||
generate_into(const NodePath &parent, const LVecBase4f &frame) {
|
||||
PT(PandaNode) new_node;
|
||||
|
||||
LPoint2f center((frame[0] + frame[1]) / 2.0f,
|
||||
(frame[2] + frame[3]) / 2.0f);
|
||||
LVecBase4f scaled_frame
|
||||
((frame[0] - center[0]) * _visible_scale[0] + center[0],
|
||||
(frame[1] - center[0]) * _visible_scale[0] + center[0],
|
||||
(frame[2] - center[1]) * _visible_scale[1] + center[1],
|
||||
(frame[3] - center[1]) * _visible_scale[1] + center[1]);
|
||||
|
||||
switch (_type) {
|
||||
case T_none:
|
||||
return NodePath();
|
||||
|
||||
case T_flat:
|
||||
new_node = generate_flat_geom(frame);
|
||||
new_node = generate_flat_geom(scaled_frame);
|
||||
break;
|
||||
|
||||
case T_bevel_out:
|
||||
new_node = generate_bevel_geom(frame, false);
|
||||
new_node = generate_bevel_geom(scaled_frame, false);
|
||||
break;
|
||||
|
||||
case T_bevel_in:
|
||||
new_node = generate_bevel_geom(frame, true);
|
||||
new_node = generate_bevel_geom(scaled_frame, true);
|
||||
break;
|
||||
|
||||
case T_groove:
|
||||
new_node = generate_groove_geom(frame, true);
|
||||
new_node = generate_groove_geom(scaled_frame, true);
|
||||
break;
|
||||
|
||||
case T_ridge:
|
||||
new_node = generate_groove_geom(frame, false);
|
||||
new_node = generate_groove_geom(scaled_frame, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ PUBLISHED:
|
|||
INLINE void set_width(const LVecBase2f &width);
|
||||
INLINE const LVecBase2f &get_width() const;
|
||||
|
||||
INLINE void set_visible_scale(float x, float y);
|
||||
INLINE void set_visible_scale(const LVecBase2f &visible_scale);
|
||||
INLINE const LVecBase2f &get_visible_scale() const;
|
||||
|
||||
LVecBase4f get_internal_frame(const LVecBase4f &frame) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
public:
|
||||
|
|
@ -81,6 +87,7 @@ private:
|
|||
Colorf _color;
|
||||
PT(Texture) _texture;
|
||||
LVecBase2f _width;
|
||||
LVecBase2f _visible_scale;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const PGFrameStyle &pfs);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,49 @@ get_region() const {
|
|||
return _region;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::set_notify
|
||||
// Access: Published
|
||||
// Description: Sets the object which will be notified when the
|
||||
// PGItem changes. Set this to NULL to disable
|
||||
// this effect. The PGItem does not retain
|
||||
// ownership of the pointer; it is your responsibility
|
||||
// to ensure that the notify object does not destruct.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_notify(PGItemNotify *notify) {
|
||||
if (_notify != (PGItemNotify *)NULL) {
|
||||
_notify->remove_item(this);
|
||||
}
|
||||
_notify = notify;
|
||||
if (_notify != (PGItemNotify *)NULL) {
|
||||
_notify->add_item(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::has_notify
|
||||
// Access: Published
|
||||
// Description: Returns true if there is an object configured to be
|
||||
// notified when the PGItem changes, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGItem::
|
||||
has_notify() const {
|
||||
return (_notify != (PGItemNotify *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::get_notify
|
||||
// Access: Published
|
||||
// Description: Returns the object which will be notified when the
|
||||
// PGItem changes, if any. Returns NULL if there
|
||||
// is no such object configured.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGItemNotify *PGItem::
|
||||
get_notify() const {
|
||||
return _notify;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::set_frame
|
||||
// Access: Published
|
||||
|
|
@ -58,9 +101,11 @@ set_frame(float left, float right, float bottom, float top) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
set_frame(const LVecBase4f &frame) {
|
||||
_has_frame = true;
|
||||
_frame = frame;
|
||||
mark_frames_stale();
|
||||
if (!_has_frame || _frame != frame) {
|
||||
_has_frame = true;
|
||||
_frame = frame;
|
||||
frame_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -96,8 +141,10 @@ has_frame() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
clear_frame() {
|
||||
_has_frame = false;
|
||||
mark_frames_stale();
|
||||
if (_has_frame) {
|
||||
_has_frame = false;
|
||||
frame_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -476,3 +523,32 @@ INLINE LMatrix4f PGItem::
|
|||
get_frame_inv_xform() const {
|
||||
return _frame_inv_xform;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::compute_area
|
||||
// Access: Private, Static
|
||||
// Description: Computes the area of the indicated frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGItem::
|
||||
compute_area(const LVecBase4f &frame) {
|
||||
return (frame[1] - frame[0]) * (frame[3] - frame[2]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::compare_largest
|
||||
// Access: Private, Static
|
||||
// Description: Given that largest is the pointer to the largest
|
||||
// frame so far, and largest_area is its area, compare
|
||||
// that to the area of the new frame; if the new frame
|
||||
// is larger, adjust largest and largest_area
|
||||
// appropriately.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGItem::
|
||||
compare_largest(const LVecBase4f *&largest, float &largest_area,
|
||||
const LVecBase4f *new_frame) {
|
||||
float new_area = compute_area(*new_frame);
|
||||
if (new_area > largest_area) {
|
||||
largest = new_frame;
|
||||
largest_area = new_area;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "pgMouseWatcherParameter.h"
|
||||
#include "pgCullTraverser.h"
|
||||
#include "config_pgui.h"
|
||||
|
||||
#include "boundingVolume.h"
|
||||
#include "pandaNode.h"
|
||||
#include "sceneGraphReducer.h"
|
||||
#include "throw_event.h"
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include "cullTraverser.h"
|
||||
#include "cullTraverserData.h"
|
||||
#include "cullBinManager.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
#include "dcast.h"
|
||||
|
||||
#ifdef HAVE_AUDIO
|
||||
|
|
@ -40,6 +41,16 @@ PT(TextNode) PGItem::_text_node;
|
|||
PGItem *PGItem::_focus_item = (PGItem *)NULL;
|
||||
PGItem::BackgroundFocus PGItem::_background_focus;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: is_right
|
||||
// Description: Returns true if the 2-d v1 is to the right of v2.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool
|
||||
is_right(const LVector2f &v1, const LVector2f &v2) {
|
||||
return (-v1[0] * v2[1] + v1[1] * v2[0]) > 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::Constructor
|
||||
// Access: Published
|
||||
|
|
@ -49,6 +60,7 @@ PGItem::
|
|||
PGItem(const string &name) :
|
||||
PandaNode(name)
|
||||
{
|
||||
_notify = NULL;
|
||||
_has_frame = false;
|
||||
_frame.set(0, 0, 0, 0);
|
||||
_region = new PGMouseWatcherRegion(this);
|
||||
|
|
@ -63,6 +75,11 @@ PGItem(const string &name) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
PGItem::
|
||||
~PGItem() {
|
||||
if (_notify != (PGItemNotify *)NULL) {
|
||||
_notify->remove_item(this);
|
||||
_notify = NULL;
|
||||
}
|
||||
|
||||
nassertv(_region->_item == this);
|
||||
_region->_item = (PGItem *)NULL;
|
||||
|
||||
|
|
@ -85,6 +102,7 @@ PGItem(const PGItem ©) :
|
|||
_state(copy._state),
|
||||
_flags(copy._flags)
|
||||
{
|
||||
_notify = NULL;
|
||||
_region = new PGMouseWatcherRegion(this);
|
||||
}
|
||||
|
||||
|
|
@ -102,38 +120,33 @@ make_copy() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::xform
|
||||
// Function: PGItem::transform_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Transforms the contents of this node by the indicated
|
||||
// matrix, if it means anything to do so. For most
|
||||
// kinds of nodes, this does nothing.
|
||||
// Description: Called after the node's transform has been changed
|
||||
// for any reason, this just provides a hook so derived
|
||||
// classes can do something special in this case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
xform(const LMatrix4f &mat) {
|
||||
// Transform the frame.
|
||||
LPoint3f ll(_frame[0], 0.0f, _frame[2]);
|
||||
LPoint3f ur(_frame[1], 0.0f, _frame[3]);
|
||||
ll = ll * mat;
|
||||
ur = ur * mat;
|
||||
_frame.set(ll[0], ur[0], ll[2], ur[2]);
|
||||
|
||||
// Transform the individual states and their frame styles.
|
||||
StateDefs::iterator di;
|
||||
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
|
||||
NodePath &root = (*di)._root;
|
||||
// Apply the matrix to the previous transform.
|
||||
root.set_transform(root.get_transform()->compose(TransformState::make_mat(mat)));
|
||||
|
||||
// Now flatten the transform into the subgraph.
|
||||
SceneGraphReducer gr;
|
||||
gr.apply_attribs(root.node());
|
||||
|
||||
// Transform the frame style too.
|
||||
if ((*di)._frame_style.xform(mat)) {
|
||||
(*di)._frame_stale = true;
|
||||
}
|
||||
transform_changed() {
|
||||
PandaNode::transform_changed();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_transform_changed(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::draw_mask_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called after the node's draw_mask has been changed
|
||||
// for any reason, this just provides a hook so derived
|
||||
// classes can do something special in this case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
draw_mask_changed() {
|
||||
PandaNode::draw_mask_changed();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_draw_mask_changed(this);
|
||||
}
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -221,8 +234,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
// which only provides one.
|
||||
sort = (bin_sort << 16) | ((sort + 0x8000) & 0xffff);
|
||||
|
||||
activate_region(transform, sort);
|
||||
pg_trav->_top->add_region(get_region());
|
||||
if (activate_region(transform, sort, data._state->get_clip_plane())) {
|
||||
pg_trav->_top->add_region(get_region());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,14 +287,53 @@ recompute_internal_bound() {
|
|||
return bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::xform
|
||||
// Access: Public, Virtual
|
||||
// Description: Transforms the contents of this node by the indicated
|
||||
// matrix, if it means anything to do so. For most
|
||||
// kinds of nodes, this does nothing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
xform(const LMatrix4f &mat) {
|
||||
// Transform the frame.
|
||||
LPoint3f ll(_frame[0], 0.0f, _frame[2]);
|
||||
LPoint3f ur(_frame[1], 0.0f, _frame[3]);
|
||||
ll = ll * mat;
|
||||
ur = ur * mat;
|
||||
_frame.set(ll[0], ur[0], ll[2], ur[2]);
|
||||
|
||||
// Transform the individual states and their frame styles.
|
||||
StateDefs::iterator di;
|
||||
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
|
||||
NodePath &root = (*di)._root;
|
||||
// Apply the matrix to the previous transform.
|
||||
root.set_transform(root.get_transform()->compose(TransformState::make_mat(mat)));
|
||||
|
||||
// Now flatten the transform into the subgraph.
|
||||
SceneGraphReducer gr;
|
||||
gr.apply_attribs(root.node());
|
||||
|
||||
// Transform the frame style too.
|
||||
if ((*di)._frame_style.xform(mat)) {
|
||||
(*di)._frame_stale = true;
|
||||
}
|
||||
}
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::activate_region
|
||||
// Access: Public
|
||||
// Description: Applies the indicated scene graph transform and order
|
||||
// as determined by the traversal from PGTop.
|
||||
//
|
||||
// The return value is true if the region is valid, or
|
||||
// false if it is empty or completely clipped.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
activate_region(const LMatrix4f &transform, int sort) {
|
||||
bool PGItem::
|
||||
activate_region(const LMatrix4f &transform, int sort,
|
||||
const ClipPlaneAttrib *cpa) {
|
||||
// Transform all four vertices, and get the new bounding box. This
|
||||
// way the region works (mostly) even if has been rotated.
|
||||
LPoint3f ll(_frame[0], 0.0f, _frame[2]);
|
||||
|
|
@ -291,10 +344,54 @@ activate_region(const LMatrix4f &transform, int sort) {
|
|||
lr = lr * transform;
|
||||
ul = ul * transform;
|
||||
ur = ur * transform;
|
||||
_region->set_frame(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
|
||||
max(max(ll[0], lr[0]), max(ul[0], ur[0])),
|
||||
min(min(ll[2], lr[2]), min(ul[2], ur[2])),
|
||||
max(max(ll[2], lr[2]), max(ul[2], ur[2])));
|
||||
|
||||
if (cpa != (ClipPlaneAttrib *)NULL && cpa->get_num_on_planes() != 0) {
|
||||
// Apply the clip plane(s) now that we are here in world space.
|
||||
|
||||
pvector<LPoint2f> points;
|
||||
points.reserve(4);
|
||||
points.push_back(LPoint2f(ll[0], ll[2]));
|
||||
points.push_back(LPoint2f(lr[0], lr[2]));
|
||||
points.push_back(LPoint2f(ur[0], ur[2]));
|
||||
points.push_back(LPoint2f(ul[0], ul[2]));
|
||||
|
||||
int num_on_planes = cpa->get_num_on_planes();
|
||||
for (int i = 0; i < num_on_planes; ++i) {
|
||||
NodePath plane_path = cpa->get_on_plane(i);
|
||||
Planef plane = DCAST(PlaneNode, plane_path.node())->get_plane();
|
||||
plane.xform(plane_path.get_net_transform()->get_mat());
|
||||
|
||||
// We ignore the y coordinate, assuming the frame is still in
|
||||
// the X-Z plane after being transformed. Not sure if we really
|
||||
// need to support general 3-D transforms on 2-D objects.
|
||||
clip_frame(points, plane);
|
||||
}
|
||||
|
||||
if (points.empty()) {
|
||||
// Turns out it's completely clipped after all.
|
||||
return false;
|
||||
}
|
||||
|
||||
pvector<LPoint2f>::iterator pi;
|
||||
pi = points.begin();
|
||||
LVecBase4f frame((*pi)[0], (*pi)[0], (*pi)[1], (*pi)[1]);
|
||||
++pi;
|
||||
while (pi != points.end()) {
|
||||
frame[0] = min(frame[0], (*pi)[0]);
|
||||
frame[1] = max(frame[1], (*pi)[0]);
|
||||
frame[2] = min(frame[2], (*pi)[1]);
|
||||
frame[3] = max(frame[3], (*pi)[1]);
|
||||
++pi;
|
||||
}
|
||||
_region->set_frame(frame);
|
||||
|
||||
} else {
|
||||
// Since there are no clip planes involved, just set the frame.
|
||||
_region->set_frame(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
|
||||
max(max(ll[0], lr[0]), max(ul[0], ur[0])),
|
||||
min(min(ll[2], lr[2]), min(ul[2], ur[2])),
|
||||
max(max(ll[2], lr[2]), max(ul[2], ur[2])));
|
||||
}
|
||||
|
||||
_region->set_sort(sort);
|
||||
_region->set_active(true);
|
||||
|
|
@ -302,6 +399,8 @@ activate_region(const LMatrix4f &transform, int sort) {
|
|||
// calculate the inverse of this transform, which is needed to
|
||||
// go back to the frame space.
|
||||
_frame_inv_xform.invert_from(transform);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -319,6 +418,11 @@ enter(const MouseWatcherParameter ¶m) {
|
|||
string event = get_enter_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_enter(this, param);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::enter()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -337,6 +441,11 @@ exit(const MouseWatcherParameter ¶m) {
|
|||
string event = get_exit_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_exit(this, param);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::exit()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -356,6 +465,11 @@ within(const MouseWatcherParameter ¶m) {
|
|||
string event = get_within_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_within(this, param);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::within()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -372,6 +486,11 @@ without(const MouseWatcherParameter ¶m) {
|
|||
string event = get_without_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_without(this, param);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::without()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -386,6 +505,11 @@ focus_in() {
|
|||
string event = get_focus_in_event();
|
||||
play_sound(event);
|
||||
throw_event(event);
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_focus_in(this);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::focus_in()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -400,6 +524,11 @@ focus_out() {
|
|||
string event = get_focus_out_event();
|
||||
play_sound(event);
|
||||
throw_event(event);
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_focus_out(this);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::focus_out()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -418,6 +547,11 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_press(this, param);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::press()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -436,6 +570,11 @@ release(const MouseWatcherParameter ¶m, bool background) {
|
|||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_release(this, param);
|
||||
}
|
||||
|
||||
//pgui_cat.info() << get_name() << "::release()" << endl;
|
||||
}
|
||||
|
||||
|
|
@ -452,6 +591,10 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||
string event = get_keystroke_event();
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_keystroke(this, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -464,6 +607,11 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||
void PGItem::
|
||||
candidate(const MouseWatcherParameter ¶m, bool background) {
|
||||
// We don't throw sound events for candidate selections for now.
|
||||
if (!background) {
|
||||
if (has_notify()) {
|
||||
get_notify()->item_candidate(this, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -474,11 +622,9 @@ candidate(const MouseWatcherParameter ¶m, bool background) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
move(const MouseWatcherParameter ¶m) {
|
||||
PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
|
||||
string event = get_press_event(param.get_button());
|
||||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
//pgui_cat.info() << get_name() << "::move()" << endl;
|
||||
if (has_notify()) {
|
||||
get_notify()->item_move(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -861,6 +1007,109 @@ play_sound(const string &event) {
|
|||
#endif // HAVE_AUDIO
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::reduce_region
|
||||
// Access: Protected
|
||||
// Description: The frame parameter is an in/out parameter. This
|
||||
// function adjusts frame so that it represents the
|
||||
// largest part of the rectangular region passed in,
|
||||
// that does not overlap with the rectangular region of
|
||||
// the indicated obscurer. If the obscurer is NULL, or
|
||||
// is a hidden node, it is not considered and the frame
|
||||
// is left unchanged.
|
||||
//
|
||||
// This is used by slider bars and scroll frames, which
|
||||
// have to automatically figure out how much space they
|
||||
// have to work with after allowing space for scroll
|
||||
// bars and buttons.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
reduce_region(LVecBase4f &frame, PGItem *obscurer) const {
|
||||
if (obscurer != (PGItem *)NULL && !obscurer->get_draw_mask().is_zero()) {
|
||||
LVecBase4f oframe = get_relative_frame(obscurer);
|
||||
|
||||
// Determine the four rectangular regions on the four sides of the
|
||||
// obscuring region.
|
||||
LVecBase4f right(max(frame[0], oframe[1]), frame[1], frame[2], frame[3]);
|
||||
LVecBase4f left(frame[0], min(frame[1], oframe[0]), frame[2], frame[3]);
|
||||
LVecBase4f above(frame[0], frame[1], max(frame[2], oframe[3]), frame[3]);
|
||||
LVecBase4f below(frame[0], frame[1], frame[2], min(frame[3], oframe[2]));
|
||||
|
||||
// Now choose the largest of those four.
|
||||
const LVecBase4f *largest = &right;
|
||||
float largest_area = compute_area(*largest);
|
||||
compare_largest(largest, largest_area, &left);
|
||||
compare_largest(largest, largest_area, &above);
|
||||
compare_largest(largest, largest_area, &below);
|
||||
|
||||
frame = *largest;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::get_relative_frame
|
||||
// Access: Protected
|
||||
// Description: Returns the LVecBase4f frame of the indicated item,
|
||||
// converted into this item's coordinate space.
|
||||
// Presumably, item is a child of this node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LVecBase4f PGItem::
|
||||
get_relative_frame(PGItem *item) const {
|
||||
NodePath this_np = NodePath::any_path((PGItem *)this);
|
||||
NodePath item_np = this_np.find_path_to(item);
|
||||
if (item_np.is_empty()) {
|
||||
item_np = NodePath::any_path(item);
|
||||
}
|
||||
const LVecBase4f &orig_frame = item->get_frame();
|
||||
LMatrix4f transform = item_np.get_mat(this_np);
|
||||
|
||||
// Transform the item's frame into the PGScrollFrame's
|
||||
// coordinate space. Transform all four vertices, and get the
|
||||
// new bounding box. This way the region works (mostly) even if
|
||||
// has been rotated.
|
||||
LPoint3f ll(orig_frame[0], 0.0f, orig_frame[2]);
|
||||
LPoint3f lr(orig_frame[1], 0.0f, orig_frame[2]);
|
||||
LPoint3f ul(orig_frame[0], 0.0f, orig_frame[3]);
|
||||
LPoint3f ur(orig_frame[1], 0.0f, orig_frame[3]);
|
||||
ll = ll * transform;
|
||||
lr = lr * transform;
|
||||
ul = ul * transform;
|
||||
ur = ur * transform;
|
||||
|
||||
return LVecBase4f(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
|
||||
max(max(ll[0], lr[0]), max(ul[0], ur[0])),
|
||||
min(min(ll[2], lr[2]), min(ul[2], ur[2])),
|
||||
max(max(ll[2], lr[2]), max(ul[2], ur[2])));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::mouse_to_local
|
||||
// Access: Protected
|
||||
// Description: Converts from the 2-d mouse coordinates into the
|
||||
// coordinate space of the item.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LPoint3f PGItem::
|
||||
mouse_to_local(const LPoint2f &mouse_point) const {
|
||||
// This is ambiguous if the PGItem has multiple instances. Why
|
||||
// would you do that, anyway?
|
||||
NodePath this_np((PGItem *)this);
|
||||
CPT(TransformState) inv_transform = NodePath().get_transform(this_np);
|
||||
return inv_transform->get_mat().xform_point(LVector3f::rfu(mouse_point[0], 0, mouse_point[1]));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when the user changes the frame size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItem::
|
||||
frame_changed() {
|
||||
mark_frames_stale();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_frame_changed(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::slot_state_def
|
||||
// Access: Private
|
||||
|
|
@ -919,3 +1168,91 @@ mark_frames_stale() {
|
|||
}
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItem::clip_frame
|
||||
// Access: Private
|
||||
// Description: Clips the four corners of the item's frame by the
|
||||
// indicated clipping plane, and modifies the points to
|
||||
// reflect the new set of clipped points.
|
||||
//
|
||||
// The return value is true if the set of points is
|
||||
// unmodified (all points are behind the clip plane), or
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PGItem::
|
||||
clip_frame(pvector<LPoint2f> &source_points, const Planef &plane) const {
|
||||
if (source_points.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LPoint3f from3d;
|
||||
LVector3f delta3d;
|
||||
if (!plane.intersects_plane(from3d, delta3d, Planef(LVector3f(0, 1, 0), LPoint3f::zero()))) {
|
||||
// The clipping plane is parallel to the polygon. The polygon is
|
||||
// either all in or all out.
|
||||
if (plane.dist_to_plane(LPoint3f::zero()) < 0.0) {
|
||||
// A point within the polygon is behind the clipping plane: the
|
||||
// polygon is all in.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Project the line of intersection into the X-Z plane. Now we have
|
||||
// a 2-d clipping line.
|
||||
LPoint2f from2d(from3d[0], from3d[2]);
|
||||
LVector2f delta2d(delta3d[0], delta3d[2]);
|
||||
|
||||
float a = -delta2d[1];
|
||||
float b = delta2d[0];
|
||||
float c = from2d[0] * delta2d[1] - from2d[1] * delta2d[0];
|
||||
|
||||
// Now walk through the points. Any point on the left of our line
|
||||
// gets removed, and the line segment clipped at the point of
|
||||
// intersection.
|
||||
|
||||
// We might increase the number of vertices by as many as 1, if the
|
||||
// plane clips off exactly one corner. (We might also decrease the
|
||||
// number of vertices, or keep them the same number.)
|
||||
pvector<LPoint2f> new_points;
|
||||
new_points.reserve(source_points.size() + 1);
|
||||
|
||||
LPoint2f last_point = source_points.back();
|
||||
bool last_is_in = !is_right(last_point - from2d, delta2d);
|
||||
bool all_in = last_is_in;
|
||||
pvector<LPoint2f>::const_iterator pi;
|
||||
for (pi = source_points.begin(); pi != source_points.end(); ++pi) {
|
||||
const LPoint2f &this_point = (*pi);
|
||||
bool this_is_in = !is_right(this_point - from2d, delta2d);
|
||||
|
||||
// There appears to be a compiler bug in gcc 4.0: we need to
|
||||
// extract this comparison outside of the if statement.
|
||||
bool crossed_over = (this_is_in != last_is_in);
|
||||
if (crossed_over) {
|
||||
// We have just crossed over the clipping line. Find the point
|
||||
// of intersection.
|
||||
LVector2f d = this_point - last_point;
|
||||
float denom = (a * d[0] + b * d[1]);
|
||||
if (denom != 0.0) {
|
||||
float t = -(a * last_point[0] + b * last_point[1] + c) / denom;
|
||||
LPoint2f p = last_point + t * d;
|
||||
|
||||
new_points.push_back(p);
|
||||
last_is_in = this_is_in;
|
||||
}
|
||||
}
|
||||
|
||||
if (this_is_in) {
|
||||
// We are behind the clipping line. Keep the point.
|
||||
new_points.push_back(this_point);
|
||||
} else {
|
||||
all_in = false;
|
||||
}
|
||||
|
||||
last_point = this_point;
|
||||
}
|
||||
|
||||
source_points.swap(new_points);
|
||||
return all_in;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "pgMouseWatcherRegion.h"
|
||||
#include "pgFrameStyle.h"
|
||||
#include "pgItemNotify.h"
|
||||
|
||||
#include "pandaNode.h"
|
||||
#include "nodePath.h"
|
||||
|
|
@ -30,12 +31,13 @@
|
|||
#include "pointerTo.h"
|
||||
#include "audioSound.h"
|
||||
#include "textNode.h"
|
||||
|
||||
#include "plane.h"
|
||||
#include "pmap.h"
|
||||
|
||||
class PGTop;
|
||||
class MouseWatcherParameter;
|
||||
class AudioSound;
|
||||
class ClipPlaneAttrib;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGItem
|
||||
|
|
@ -60,14 +62,18 @@ protected:
|
|||
PGItem(const PGItem ©);
|
||||
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
virtual void transform_changed();
|
||||
virtual void draw_mask_changed();
|
||||
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
virtual BoundingVolume *recompute_internal_bound();
|
||||
|
||||
public:
|
||||
void activate_region(const LMatrix4f &transform, int sort);
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
bool activate_region(const LMatrix4f &transform, int sort,
|
||||
const ClipPlaneAttrib *cpa);
|
||||
INLINE PGMouseWatcherRegion *get_region() const;
|
||||
|
||||
virtual void enter(const MouseWatcherParameter ¶m);
|
||||
|
|
@ -87,6 +93,10 @@ public:
|
|||
static void background_keystroke(const MouseWatcherParameter ¶m);
|
||||
static void background_candidate(const MouseWatcherParameter ¶m);
|
||||
|
||||
INLINE void set_notify(PGItemNotify *notify);
|
||||
INLINE bool has_notify() const;
|
||||
INLINE PGItemNotify *get_notify() const;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_frame(float left, float right, float bottom, float top);
|
||||
INLINE void set_frame(const LVecBase4f &frame);
|
||||
|
|
@ -158,11 +168,28 @@ PUBLISHED:
|
|||
protected:
|
||||
void play_sound(const string &event);
|
||||
|
||||
void reduce_region(LVecBase4f &clip, PGItem *obscurer) const;
|
||||
void reduce_region(LVecBase4f &frame, float px, float py) const;
|
||||
LVecBase4f get_relative_frame(PGItem *item) const;
|
||||
LPoint3f mouse_to_local(const LPoint2f &mouse_point) const;
|
||||
|
||||
virtual void frame_changed();
|
||||
|
||||
private:
|
||||
void slot_state_def(int state);
|
||||
void update_frame(int state);
|
||||
void mark_frames_stale();
|
||||
|
||||
INLINE static float compute_area(const LVecBase4f &frame);
|
||||
INLINE static void compare_largest(const LVecBase4f *&largest,
|
||||
float &largest_area,
|
||||
const LVecBase4f *new_frame);
|
||||
|
||||
bool clip_frame(pvector<LPoint2f> &source_points, const Planef &plane) const;
|
||||
|
||||
private:
|
||||
PGItemNotify *_notify;
|
||||
|
||||
bool _has_frame;
|
||||
LVecBase4f _frame;
|
||||
int _state;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Filename: pgItemNotify.I
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGItemNotify::
|
||||
PGItemNotify() {
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
// Filename: pgItemNotify.cxx
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgItemNotify.h"
|
||||
#include "pgItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGItemNotify::
|
||||
~PGItemNotify() {
|
||||
while (!_items.empty()) {
|
||||
// Disconnect all of the items that are connected to this
|
||||
// object.
|
||||
PGItem *item = (*_items.begin());
|
||||
nassertv(item->get_notify() == this);
|
||||
(*_items.begin())->set_notify(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_transform_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's local transform
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_transform_changed(PGItem *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's frame
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_frame_changed(PGItem *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_draw_mask_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's draw_mask
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_draw_mask_changed(PGItem *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_enter
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "enter" event is triggered on a
|
||||
// watched PGItem. See PGItem::enter().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_enter(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_exit
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "exit" event is triggered on a
|
||||
// watched PGItem. See PGItem::exit().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_exit(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_within
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "within" event is triggered on a
|
||||
// watched PGItem. See PGItem::within().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_within(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_without
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "without" event is triggered on a
|
||||
// watched PGItem. See PGItem::without().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_without(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_focus_in
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "focus_in" event is triggered on a
|
||||
// watched PGItem. See PGItem::focus_in().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_focus_in(PGItem *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_focus_out
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "focus_out" event is triggered on a
|
||||
// watched PGItem. See PGItem::focus_out().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_focus_out(PGItem *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_press
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "press" event is triggered on a
|
||||
// watched PGItem. See PGItem::press().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_press(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_release
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "release" event is triggered on a
|
||||
// watched PGItem. See PGItem::release().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_release(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_keystroke
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "keystroke" event is triggered on a
|
||||
// watched PGItem. See PGItem::keystroke().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_keystroke(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_candidate
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "candidate" event is triggered on a
|
||||
// watched PGItem. See PGItem::candidate().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_candidate(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::item_move
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "move" event is triggered on a
|
||||
// watched PGItem. See PGItem::move().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
item_move(PGItem *, const MouseWatcherParameter &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::add_item
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by PGItem when a new item is set up to
|
||||
// notify this object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
add_item(PGItem *item) {
|
||||
bool inserted = _items.insert(item).second;
|
||||
nassertv(inserted);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGItemNotify::remove_item
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by PGItem when an item is no longer set up
|
||||
// to notify this object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGItemNotify::
|
||||
remove_item(PGItem *item) {
|
||||
Items::iterator bi;
|
||||
bi = _items.find(item);
|
||||
nassertv(bi != _items.end());
|
||||
_items.erase(bi);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// Filename: pgItemNotify.h
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGITEMNOTIFY_H
|
||||
#define PGITEMNOTIFY_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
class PGItem;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGItemNotify
|
||||
// Description : Objects that inherit from this class can receive
|
||||
// specialized messages when PGItems change in certain
|
||||
// ways.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGItemNotify {
|
||||
public:
|
||||
INLINE PGItemNotify();
|
||||
virtual ~PGItemNotify();
|
||||
|
||||
protected:
|
||||
virtual void item_transform_changed(PGItem *item);
|
||||
virtual void item_frame_changed(PGItem *item);
|
||||
virtual void item_draw_mask_changed(PGItem *item);
|
||||
|
||||
virtual void item_enter(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_exit(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_within(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_without(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_focus_in(PGItem *item);
|
||||
virtual void item_focus_out(PGItem *item);
|
||||
virtual void item_press(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_release(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_keystroke(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_candidate(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_move(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
|
||||
protected:
|
||||
void add_item(PGItem *item);
|
||||
void remove_item(PGItem *item);
|
||||
|
||||
private:
|
||||
typedef pset<PGItem *> Items;
|
||||
Items _items;
|
||||
|
||||
friend class PGItem;
|
||||
};
|
||||
|
||||
#include "pgItemNotify.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
// Filename: pgScrollFrame.I
|
||||
// Created by: drose (17Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::set_virtual_frame
|
||||
// Access: Published
|
||||
// Description: Sets the bounding rectangle of the virtual frame.
|
||||
// This is the size of the large, virtual canvas which
|
||||
// we can see only a portion of at any given time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_virtual_frame(float left, float right, float bottom, float top) {
|
||||
set_virtual_frame(LVecBase4f(left, right, bottom, top));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::set_virtual_frame
|
||||
// Access: Published
|
||||
// Description: Sets the bounding rectangle of the virtual frame.
|
||||
// This is the size of the large, virtual canvas which
|
||||
// we can see only a portion of at any given time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_virtual_frame(const LVecBase4f &frame) {
|
||||
_has_virtual_frame = true;
|
||||
_virtual_frame = frame;
|
||||
|
||||
if (_auto_hide) {
|
||||
_needs_remanage = true;
|
||||
}
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::get_virtual_frame
|
||||
// Access: Published
|
||||
// Description: Returns the bounding rectangle of the virtual frame.
|
||||
// See set_virtual_frame(). If has_virtual_frame() is
|
||||
// false, this returns the item's clip frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase4f &PGScrollFrame::
|
||||
get_virtual_frame() const {
|
||||
return _has_virtual_frame ? _virtual_frame : get_clip_frame();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::has_virtual_frame
|
||||
// Access: Published
|
||||
// Description: Returns true if the virtual frame has a bounding
|
||||
// rectangle; see set_virtual_frame(). Most
|
||||
// PGScrollFrame objects will have a virtual frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGScrollFrame::
|
||||
has_virtual_frame() const {
|
||||
return _has_virtual_frame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::clear_virtual_frame
|
||||
// Access: Published
|
||||
// Description: Removes the virtual frame from the item. This
|
||||
// effectively sets the virtual frame to the same size
|
||||
// as the clip frame. Scrolling will no longer be
|
||||
// possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
clear_virtual_frame() {
|
||||
_has_virtual_frame = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::set_manage_pieces
|
||||
// Access: Published
|
||||
// Description: Sets the manage_pieces flag. When this is true, the
|
||||
// sub-pieces of the scroll frame--that is, the two
|
||||
// scroll bars--are automatically positioned and/or
|
||||
// resized when the scroll frame's overall frame is
|
||||
// changed. They are also automatically resized to fill
|
||||
// in the gap when one or the other is hidden.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_manage_pieces(bool manage_pieces) {
|
||||
_manage_pieces = manage_pieces;
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::get_manage_pieces
|
||||
// Access: Published
|
||||
// Description: Returns the manage_pieces flag. See
|
||||
// set_manage_pieces().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGScrollFrame::
|
||||
get_manage_pieces() const {
|
||||
return _manage_pieces;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::set_auto_hide
|
||||
// Access: Published
|
||||
// Description: Sets the auto_hide flag. When this is true, the
|
||||
// two scroll bars are automatically hidden if they are
|
||||
// not needed (that is, if the virtual frame would fit
|
||||
// within the clip frame without them), and they are
|
||||
// automatically shown when they are needed.
|
||||
//
|
||||
// Setting this flag true forces the manage_pieces flag
|
||||
// to also be set true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_auto_hide(bool auto_hide) {
|
||||
_auto_hide = auto_hide;
|
||||
if (_auto_hide) {
|
||||
set_manage_pieces(true);
|
||||
_needs_remanage = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::get_auto_hide
|
||||
// Access: Published
|
||||
// Description: Returns the auto_hide flag. See
|
||||
// set_auto_hide().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGScrollFrame::
|
||||
get_auto_hide() const {
|
||||
return _auto_hide;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::set_horizontal_slider
|
||||
// Access: Published
|
||||
// Description: Sets the PGSliderBar object that will serve as the
|
||||
// horizontal scroll bar for this frame. It is your
|
||||
// responsibility to parent this slider bar to the frame
|
||||
// and move it to the appropriate place.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_horizontal_slider(PGSliderBar *horizontal_slider) {
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
_horizontal_slider->set_notify(NULL);
|
||||
}
|
||||
_horizontal_slider = horizontal_slider;
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
_horizontal_slider->set_notify(this);
|
||||
}
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::clear_horizontal_slider
|
||||
// Access: Published
|
||||
// Description: Removes the horizontal scroll bar from control of the
|
||||
// frame. It is your responsibility to actually remove
|
||||
// or hide the object itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
clear_horizontal_slider() {
|
||||
set_horizontal_slider(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::get_horizontal_slider
|
||||
// Access: Published
|
||||
// Description: Returns the PGSliderBar that serves as the horizontal
|
||||
// scroll bar for this frame, if any, or NULL if it is
|
||||
// not set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGSliderBar *PGScrollFrame::
|
||||
get_horizontal_slider() const {
|
||||
return _horizontal_slider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::set_vertical_slider
|
||||
// Access: Published
|
||||
// Description: Sets the PGSliderBar object that will serve as the
|
||||
// vertical scroll bar for this frame. It is your
|
||||
// responsibility to parent this slider bar to the frame
|
||||
// and move it to the appropriate place.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
set_vertical_slider(PGSliderBar *vertical_slider) {
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
_vertical_slider->set_notify(NULL);
|
||||
}
|
||||
_vertical_slider = vertical_slider;
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
_vertical_slider->set_notify(this);
|
||||
}
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::clear_vertical_slider
|
||||
// Access: Published
|
||||
// Description: Removes the vertical scroll bar from control of the
|
||||
// frame. It is your responsibility to actually remove
|
||||
// or hide the object itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
clear_vertical_slider() {
|
||||
set_vertical_slider(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::get_vertical_slider
|
||||
// Access: Published
|
||||
// Description: Returns the PGSliderBar that serves as the vertical
|
||||
// scroll bar for this frame, if any, or NULL if it is
|
||||
// not set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGSliderBar *PGScrollFrame::
|
||||
get_vertical_slider() const {
|
||||
return _vertical_slider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::recompute
|
||||
// Access: Published
|
||||
// Description: Forces the PGScrollFrame to recompute itself right
|
||||
// now. Normally this should not be required.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGScrollFrame::
|
||||
recompute() {
|
||||
recompute_clip();
|
||||
recompute_canvas();
|
||||
}
|
||||
|
|
@ -0,0 +1,445 @@
|
|||
// Filename: pgScrollFrame.cxx
|
||||
// Created by: drose (17Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgScrollFrame.h"
|
||||
|
||||
TypeHandle PGScrollFrame::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGScrollFrame::
|
||||
PGScrollFrame(const string &name) : PGVirtualFrame(name)
|
||||
{
|
||||
_needs_remanage = false;
|
||||
_needs_recompute_canvas = false;
|
||||
_needs_recompute_clip = false;
|
||||
_has_virtual_frame = false;
|
||||
_virtual_frame.set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
_manage_pieces = false;
|
||||
_auto_hide = false;
|
||||
_horizontal_slider = NULL;
|
||||
_vertical_slider = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGScrollFrame::
|
||||
~PGScrollFrame() {
|
||||
set_horizontal_slider(NULL);
|
||||
set_vertical_slider(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::Copy Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGScrollFrame::
|
||||
PGScrollFrame(const PGScrollFrame ©) :
|
||||
PGVirtualFrame(copy),
|
||||
_has_virtual_frame(copy._has_virtual_frame),
|
||||
_virtual_frame(copy._virtual_frame),
|
||||
_manage_pieces(copy._manage_pieces),
|
||||
_auto_hide(copy._auto_hide)
|
||||
{
|
||||
_needs_remanage = false;
|
||||
_needs_recompute_canvas = true;
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGScrollFrame::
|
||||
make_copy() const {
|
||||
return new PGScrollFrame(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::has_cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: Should be overridden by derived classes to return
|
||||
// true if cull_callback() has been defined. Otherwise,
|
||||
// returns false to indicate cull_callback() does not
|
||||
// need to be called for this node during the cull
|
||||
// traversal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PGScrollFrame::
|
||||
has_cull_callback() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::cull_callback
|
||||
// Access: Protected, Virtual
|
||||
// Description: If has_cull_callback() returns true, this function
|
||||
// will be called during the cull traversal to perform
|
||||
// any additional operations that should be performed at
|
||||
// cull time. This may include additional manipulation
|
||||
// of render state or additional visible/invisible
|
||||
// decisions, or any other arbitrary operation.
|
||||
//
|
||||
// By the time this function is called, the node has
|
||||
// already passed the bounding-volume test for the
|
||||
// viewing frustum, and the node's transform and state
|
||||
// have already been applied to the indicated
|
||||
// CullTraverserData object.
|
||||
//
|
||||
// The return value is true if this node should be
|
||||
// visible, or false if it should be culled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PGScrollFrame::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
if (_manage_pieces && _needs_remanage) {
|
||||
remanage();
|
||||
}
|
||||
if (_needs_recompute_clip) {
|
||||
recompute_clip();
|
||||
}
|
||||
if (_needs_recompute_canvas) {
|
||||
recompute_canvas();
|
||||
}
|
||||
return PGVirtualFrame::cull_callback(trav, data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::xform
|
||||
// Access: Public, Virtual
|
||||
// Description: Transforms the contents of this node by the indicated
|
||||
// matrix, if it means anything to do so. For most
|
||||
// kinds of nodes, this does nothing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
xform(const LMatrix4f &mat) {
|
||||
PGVirtualFrame::xform(mat);
|
||||
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::setup
|
||||
// Access: Published
|
||||
// Description: Creates a PGScrollFrame with the indicated
|
||||
// dimensions, and the indicated virtual frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
setup(float width, float height,
|
||||
float left, float right, float bottom, float top,
|
||||
float slider_width, float bevel) {
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
set_frame(0, width, 0, height);
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_width(bevel, bevel);
|
||||
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
style.set_type(PGFrameStyle::T_ridge);
|
||||
set_frame_style(0, style);
|
||||
|
||||
set_clip_frame(bevel, width - bevel,
|
||||
bevel, height - bevel);
|
||||
|
||||
set_virtual_frame(left, right, bottom, top);
|
||||
|
||||
// Remove the slider nodes created by a previous call to setup(), if
|
||||
// any.
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
remove_child(_horizontal_slider);
|
||||
set_horizontal_slider(NULL);
|
||||
}
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
remove_child(_vertical_slider);
|
||||
set_vertical_slider(NULL);
|
||||
}
|
||||
|
||||
// Create new slider bars.
|
||||
PT(PGSliderBar) horizontal_slider = new PGSliderBar("horizontal");
|
||||
horizontal_slider->setup_scroll_bar(false, width - slider_width - bevel * 2, slider_width, bevel);
|
||||
horizontal_slider->set_transform(TransformState::make_pos(LVector3f::rfu(width / 2.0f - slider_width / 2.0f, 0, slider_width / 2.0f + bevel)));
|
||||
add_child(horizontal_slider);
|
||||
set_horizontal_slider(horizontal_slider);
|
||||
|
||||
PT(PGSliderBar) vertical_slider = new PGSliderBar("vertical");
|
||||
vertical_slider->setup_scroll_bar(true, width - slider_width - bevel * 2, slider_width, bevel);
|
||||
add_child(vertical_slider);
|
||||
vertical_slider->set_transform(TransformState::make_pos(LVector3f::rfu(width - slider_width / 2.0f - bevel, 0, width / 2.0f + slider_width / 2.0f)));
|
||||
set_vertical_slider(vertical_slider);
|
||||
|
||||
set_manage_pieces(true);
|
||||
set_auto_hide(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::remanage
|
||||
// Access: Published
|
||||
// Description: Manages the position and size of the scroll bars.
|
||||
// Normally this should not need to be called directly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
remanage() {
|
||||
_needs_remanage = false;
|
||||
|
||||
const LVecBase4f &frame = get_frame();
|
||||
LVecBase4f clip = get_frame_style(get_state()).get_internal_frame(frame);
|
||||
|
||||
// Determine which scroll bars we have in the frame.
|
||||
|
||||
bool got_horizontal = false;
|
||||
float horizontal_width = 0.0f;
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
got_horizontal = true;
|
||||
const LVecBase4f &slider_frame = _horizontal_slider->get_frame();
|
||||
horizontal_width = slider_frame[3] - slider_frame[2];
|
||||
}
|
||||
|
||||
bool got_vertical = false;
|
||||
float vertical_width = 0.0f;
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
got_vertical = true;
|
||||
const LVecBase4f &slider_frame = _vertical_slider->get_frame();
|
||||
vertical_width = slider_frame[1] - slider_frame[0];
|
||||
}
|
||||
|
||||
if (_auto_hide) {
|
||||
// Should we hide or show either of the scroll bars? TODO.
|
||||
|
||||
// Start by figuring out what our maximum clipping area will be.
|
||||
float clip_width = clip[1] - clip[0];
|
||||
float clip_height = clip[3] - clip[2];
|
||||
|
||||
// And our virtual frame too.
|
||||
const LVecBase4f &virtual_frame = get_virtual_frame();
|
||||
float virtual_width = virtual_frame[1] - virtual_frame[0];
|
||||
float virtual_height = virtual_frame[3] - virtual_frame[2];
|
||||
|
||||
if (virtual_width <= clip_width &&
|
||||
virtual_height <= clip_height) {
|
||||
// No need for either slider.
|
||||
got_horizontal = false;
|
||||
got_vertical = false;
|
||||
|
||||
} else {
|
||||
if (virtual_width <= clip_width - vertical_width) {
|
||||
// No need for the horizontal slider.
|
||||
got_horizontal = false;
|
||||
}
|
||||
|
||||
if (virtual_height <= clip_height - horizontal_width) {
|
||||
// No need for the vertical slider.
|
||||
got_vertical = false;
|
||||
|
||||
// Now reconsider the need for the horizontal slider.
|
||||
if (virtual_width <= clip_width) {
|
||||
got_horizontal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now show or hide the sliders appropriately.
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
if (got_horizontal) {
|
||||
_horizontal_slider->set_draw_mask(DrawMask::all_on());
|
||||
} else {
|
||||
_horizontal_slider->set_draw_mask(DrawMask::all_off());
|
||||
_horizontal_slider->set_ratio(0.0f);
|
||||
horizontal_width = 0.0f;
|
||||
}
|
||||
}
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
if (got_vertical) {
|
||||
_vertical_slider->set_draw_mask(DrawMask::all_on());
|
||||
} else {
|
||||
_vertical_slider->set_draw_mask(DrawMask::all_off());
|
||||
_vertical_slider->set_ratio(0.0f);
|
||||
vertical_width = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Showing or hiding one of the scroll bars might have set this
|
||||
// flag again indirectly; we clear it again to avoid a feedback
|
||||
// loop.
|
||||
_needs_remanage = false;
|
||||
}
|
||||
|
||||
// Are either or both of the scroll bars hidden?
|
||||
if (got_horizontal && _horizontal_slider->get_draw_mask().is_zero()) {
|
||||
got_horizontal = false;
|
||||
horizontal_width = 0.0f;
|
||||
}
|
||||
if (got_vertical && _vertical_slider->get_draw_mask().is_zero()) {
|
||||
got_vertical = false;
|
||||
vertical_width = 0.0f;
|
||||
}
|
||||
|
||||
if (got_horizontal) {
|
||||
_horizontal_slider->set_frame(clip[0], clip[1] - vertical_width,
|
||||
clip[2], clip[2] + horizontal_width);
|
||||
_horizontal_slider->clear_transform();
|
||||
}
|
||||
if (got_vertical) {
|
||||
_vertical_slider->set_frame(clip[1] - vertical_width, clip[1],
|
||||
clip[2] + horizontal_width, clip[3]);
|
||||
_vertical_slider->clear_transform();
|
||||
}
|
||||
|
||||
|
||||
recompute();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when the user changes the frame size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
frame_changed() {
|
||||
PGVirtualFrame::frame_changed();
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::item_transform_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's local transform
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
item_transform_changed(PGItem *) {
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::item_frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's frame
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
item_frame_changed(PGItem *) {
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::item_draw_mask_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's draw_mask
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
item_draw_mask_changed(PGItem *) {
|
||||
_needs_remanage = true;
|
||||
_needs_recompute_clip = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::slider_bar_adjust
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGSliderBar's value
|
||||
// has been changed by the user or programmatically.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
slider_bar_adjust(PGSliderBar *) {
|
||||
_needs_recompute_canvas = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::recompute_clip
|
||||
// Access: Private
|
||||
// Description: Recomputes the clipping window of the PGScrollFrame,
|
||||
// based on the position of the slider bars.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
recompute_clip() {
|
||||
_needs_recompute_clip = false;
|
||||
_needs_recompute_canvas = true;
|
||||
|
||||
// Figure out how to remove the scroll bars from the clip region.
|
||||
LVecBase4f clip = get_frame_style(get_state()).get_internal_frame(get_frame());
|
||||
reduce_region(clip, _horizontal_slider);
|
||||
reduce_region(clip, _vertical_slider);
|
||||
|
||||
set_clip_frame(clip);
|
||||
|
||||
if (_horizontal_slider != (PGSliderBar *)NULL) {
|
||||
_horizontal_slider->set_page_size((clip[1] - clip[0]) / (_virtual_frame[1] - _virtual_frame[0]));
|
||||
}
|
||||
if (_vertical_slider != (PGSliderBar *)NULL) {
|
||||
_vertical_slider->set_page_size((clip[3] - clip[2]) / (_virtual_frame[3] - _virtual_frame[2]));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::recompute_canvas
|
||||
// Access: Private
|
||||
// Description: Recomputes the portion of the virtual canvas that is
|
||||
// visible within the PGScrollFrame, based on the values
|
||||
// of the slider bars.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGScrollFrame::
|
||||
recompute_canvas() {
|
||||
_needs_recompute_canvas = false;
|
||||
|
||||
const LVecBase4f &clip = get_clip_frame();
|
||||
|
||||
float x = interpolate_canvas(clip[0], clip[1],
|
||||
_virtual_frame[0], _virtual_frame[1],
|
||||
_horizontal_slider);
|
||||
|
||||
float y = interpolate_canvas(clip[3], clip[2],
|
||||
_virtual_frame[3], _virtual_frame[2],
|
||||
_vertical_slider);
|
||||
|
||||
get_canvas_node()->set_transform(TransformState::make_pos(LVector3f::rfu(x, 0, y)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGScrollFrame::interpolate_canvas
|
||||
// Access: Private
|
||||
// Description: Computes the linear translation that should be
|
||||
// applied to the virtual canvas node, based on the
|
||||
// corresponding slider bar's position.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
float PGScrollFrame::
|
||||
interpolate_canvas(float clip_min, float clip_max,
|
||||
float canvas_min, float canvas_max,
|
||||
PGSliderBar *slider_bar) {
|
||||
float t = 0.0f;
|
||||
if (slider_bar != (PGSliderBar *)NULL) {
|
||||
t = slider_bar->get_ratio();
|
||||
}
|
||||
|
||||
float min = clip_min - canvas_min;
|
||||
float max = clip_max - canvas_max;
|
||||
|
||||
return min + t * (max - min);
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
// Filename: pgScrollFrame.h
|
||||
// Created by: drose (17Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGSCROLLFRAME_H
|
||||
#define PGSCROLLFRAME_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pgVirtualFrame.h"
|
||||
#include "pgSliderBarNotify.h"
|
||||
#include "pgSliderBar.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGScrollFrame
|
||||
// Description : This is a special kind of frame that pretends to be
|
||||
// much larger than it actually is. You can scroll
|
||||
// through the frame, as if you're looking through a
|
||||
// window at the larger frame beneath. All children of
|
||||
// this frame node are scrolled and clipped as if they
|
||||
// were children of the larger, virtual frame.
|
||||
//
|
||||
// This is implemented as a specialization of
|
||||
// PGVirtualFrame, which handles the meat of the virtual
|
||||
// canvas. This class adds automatic support for scroll
|
||||
// bars, and restricts the virtual transform to
|
||||
// translate only (no scale or rotate).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGScrollFrame : public PGVirtualFrame, public PGSliderBarNotify {
|
||||
PUBLISHED:
|
||||
PGScrollFrame(const string &name = "");
|
||||
virtual ~PGScrollFrame();
|
||||
|
||||
protected:
|
||||
PGScrollFrame(const PGScrollFrame ©);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
|
||||
PUBLISHED:
|
||||
void setup(float width, float height,
|
||||
float left, float right, float bottom, float top,
|
||||
float slider_width, float bevel);
|
||||
|
||||
INLINE void set_virtual_frame(float left, float right, float bottom, float top);
|
||||
INLINE void set_virtual_frame(const LVecBase4f &virtual_frame);
|
||||
INLINE const LVecBase4f &get_virtual_frame() const;
|
||||
INLINE bool has_virtual_frame() const;
|
||||
INLINE void clear_virtual_frame();
|
||||
|
||||
INLINE void set_manage_pieces(bool manage_pieces);
|
||||
INLINE bool get_manage_pieces() const;
|
||||
|
||||
INLINE void set_auto_hide(bool auto_hide);
|
||||
INLINE bool get_auto_hide() const;
|
||||
|
||||
INLINE void set_horizontal_slider(PGSliderBar *horizontal_slider);
|
||||
INLINE void clear_horizontal_slider();
|
||||
INLINE PGSliderBar *get_horizontal_slider() const;
|
||||
|
||||
INLINE void set_vertical_slider(PGSliderBar *vertical_slider);
|
||||
INLINE void clear_vertical_slider();
|
||||
INLINE PGSliderBar *get_vertical_slider() const;
|
||||
|
||||
void remanage();
|
||||
INLINE void recompute();
|
||||
|
||||
protected:
|
||||
virtual void frame_changed();
|
||||
|
||||
virtual void item_transform_changed(PGItem *item);
|
||||
virtual void item_frame_changed(PGItem *item);
|
||||
virtual void item_draw_mask_changed(PGItem *item);
|
||||
virtual void slider_bar_adjust(PGSliderBar *slider_bar);
|
||||
|
||||
private:
|
||||
void recompute_clip();
|
||||
|
||||
void recompute_canvas();
|
||||
float interpolate_canvas(float clip_min, float clip_max,
|
||||
float canvas_min, float canvas_max,
|
||||
PGSliderBar *slider_bar);
|
||||
|
||||
private:
|
||||
bool _needs_remanage;
|
||||
bool _needs_recompute_clip;
|
||||
bool _needs_recompute_canvas;
|
||||
|
||||
LVecBase4f _orig_clip_frame;
|
||||
|
||||
bool _has_virtual_frame;
|
||||
LVecBase4f _virtual_frame;
|
||||
|
||||
bool _manage_pieces;
|
||||
bool _auto_hide;
|
||||
|
||||
PT(PGSliderBar) _horizontal_slider;
|
||||
PT(PGSliderBar) _vertical_slider;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PGVirtualFrame::init_type();
|
||||
register_type(_type_handle, "PGScrollFrame",
|
||||
PGVirtualFrame::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "pgScrollFrame.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -17,265 +17,419 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_notify
|
||||
// Access: Published
|
||||
// Description: Sets the object which will be notified when the
|
||||
// PGSliderBar changes. Set this to NULL to disable
|
||||
// this effect. The PGSliderBar does not retain
|
||||
// ownership of the pointer; it is your responsibility
|
||||
// to ensure that the notify object does not destruct.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_notify(PGSliderBarNotify *notify) {
|
||||
PGItem::set_notify(notify);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_notify
|
||||
// Access: Published
|
||||
// Description: Returns the object which will be notified when the
|
||||
// PGSliderBar changes, if any. Returns NULL if there
|
||||
// is no such object configured.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGSliderBarNotify *PGSliderBar::
|
||||
get_notify() const {
|
||||
return (PGSliderBarNotify *)PGItem::get_notify();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_axis
|
||||
// Access: Published
|
||||
// Description: Specifies the axis of the slider bar's motion. This
|
||||
// should be only one of four vectors: (1, 0, 0), (0, 0,
|
||||
// 1), (-1, 0, 0), or (0, 0, -1).
|
||||
//
|
||||
// This specifies the vector in which the thumb moves
|
||||
// when it is moving from the minimum to the maximum
|
||||
// value.
|
||||
//
|
||||
// The axis must be parallel to one of the screen axes,
|
||||
// and it must be normalized. Hence, it may only be one
|
||||
// of the above four possibilities; anything else is an
|
||||
// error and will result in indeterminate behavior.
|
||||
//
|
||||
// Normally, you should not try to set the axis
|
||||
// directly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_axis(const LVector3f &axis) {
|
||||
_axis = axis;
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_axis
|
||||
// Access: Published
|
||||
// Description: Returns the axis of the slider bar's motion. See
|
||||
// set_axis().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVector3f &PGSliderBar::
|
||||
get_axis() const {
|
||||
return _axis;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_range
|
||||
// Access: Published
|
||||
// Description: Sets the value at which the SliderBar indicates 100%.
|
||||
// Description: Sets the minimum and maxmimum value for the slider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_range(float range) {
|
||||
_range = range;
|
||||
_bar_state = -1;
|
||||
set_range(float min_value, float max_value) {
|
||||
nassertv(min_value != max_value);
|
||||
_min_value = min_value;
|
||||
_max_value = max_value;
|
||||
_needs_recompute = true;
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->slider_bar_set_range(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_range
|
||||
// Function: PGSliderBar::get_min_value
|
||||
// Access: Published
|
||||
// Description: Returns the value at which the SliderBar indicates 100%.
|
||||
// Description: Returns the value when the slider is all the way to
|
||||
// the left.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_range() const {
|
||||
return _range;
|
||||
get_min_value() const {
|
||||
return _min_value;
|
||||
}
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_magnifier
|
||||
// Function: PGSliderBar::get_max_value
|
||||
// Access: Published
|
||||
// Description: Sets a magnifier value for the mouseWatcherRegion in
|
||||
// the Y direction.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_magnifier(float value) {
|
||||
PGItem::_mouseWatcherMagnifier = value;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_value
|
||||
// Access: Published
|
||||
// Description: Returns the current value of the bar.
|
||||
// Description: Returns the value when the slider is all the way to
|
||||
// the right.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_magnifier() const {
|
||||
return PGItem::_mouseWatcherMagnifier;
|
||||
get_max_value() const {
|
||||
return _max_value;
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_scroll_size
|
||||
// Access: Published
|
||||
// Description: Specifies the amount the slider will move when the
|
||||
// user clicks on the left or right buttons.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_scroll_size(float value) {
|
||||
_scroll_value = value;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_scroll_size
|
||||
// Access: Published
|
||||
// Description: Returns the value last set by set_scroll_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_scroll_size() const {
|
||||
return _scroll_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_page_size
|
||||
// Access: Published
|
||||
// Description: Specifies the amount of data contained in a single
|
||||
// page. This indicates how much the thumb will jump
|
||||
// when the trough is directly clicked; and if
|
||||
// resize_thumb is true, it also controls the visible
|
||||
// size of the thumb button.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_page_size(float value) {
|
||||
_page_value = value;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_page_size
|
||||
// Access: Published
|
||||
// Description: Returns the value last set by set_page_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_page_size() const {
|
||||
return _page_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_value
|
||||
// Access: Published
|
||||
// Description: Sets the current value of the bar. This should range
|
||||
// between 0 and get_range().
|
||||
// Description: Sets the current value of the slider
|
||||
// programmatically. This should range between
|
||||
// get_min_value() and get_max_value().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_value(float value) {
|
||||
_value = value;
|
||||
_mapped_value = _negative_mapping ? (_value*0.5 + 0.5) : _value;
|
||||
_update_x = _width * (2*_mapped_value - 1);
|
||||
_bar_state = -1;
|
||||
_update_slider = true;
|
||||
set_ratio((value - _min_value) / (_max_value - _min_value));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_value
|
||||
// Access: Published
|
||||
// Description: Returns the current value of the bar.
|
||||
// Description: Returns the current value of the slider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_value() const {
|
||||
return _value;
|
||||
return get_ratio() * (_max_value - _min_value) + _min_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar:get_mapped_value
|
||||
// Function: PGSliderBar::set_ratio
|
||||
// Access: Published
|
||||
// Description: Returns the _mapped_value which is caluclated from
|
||||
// _value with negative_mapping bool
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_mapped_value() const {
|
||||
return _mapped_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_update_x
|
||||
// Access: Published
|
||||
// Description: Returns the _update_x which is caluclated from
|
||||
// _mapped_value with width formula
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_update_x() const {
|
||||
return _update_x;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_update_y
|
||||
// Access: Published
|
||||
// Description: Returns the _update_y which is caluclated from
|
||||
// _mapped_value with width formula
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_update_y() const {
|
||||
return _update_y;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_speed
|
||||
// Access: Published
|
||||
// Description: Sets the current speed at which the slider moves
|
||||
// Description: Sets the current value of the slider, expressed in
|
||||
// the range 0 .. 1.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_speed(float speed) {
|
||||
_speed = speed;
|
||||
set_ratio(float ratio) {
|
||||
_ratio = max(min(ratio, 1.0f), 0.0f);
|
||||
_needs_reposition = true;
|
||||
adjust();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_speed
|
||||
// Function: PGSliderBar::get_ratio
|
||||
// Access: Published
|
||||
// Description: Returns the current speed at which the slider moves.
|
||||
// Description: Returns the current value of the slider, expressed in
|
||||
// the range 0 .. 1.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_speed() const {
|
||||
return _speed;
|
||||
get_ratio() const {
|
||||
return _ratio;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_scale
|
||||
// Function: PGSliderBar::set_resize_thumb
|
||||
// Access: Published
|
||||
// Description: Sets the scale of the traugh image
|
||||
// Description: Sets the resize_thumb flag. When this is true, the
|
||||
// thumb button's frame will be adjusted so that its
|
||||
// width visually represents the page size. When this
|
||||
// is false, the thumb button will be left alone.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_scale(float scale) {
|
||||
_scale = scale/10;
|
||||
set_resize_thumb(bool resize_thumb) {
|
||||
_resize_thumb = resize_thumb;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_scale
|
||||
// Function: PGSliderBar::get_resize_thumb
|
||||
// Access: Published
|
||||
// Description: Returns the scale set on the traugh image
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float PGSliderBar::
|
||||
get_scale() const {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_slider_only
|
||||
// Access: Published
|
||||
// Description: Sets _slider_only. True:only slider button desired.
|
||||
// No left or right button to control slider needed.
|
||||
// Else, the left and right slider buttons are shown.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_slider_only(bool value) {
|
||||
_slider_only = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_slider_only
|
||||
// Access: Published
|
||||
// Description: Returns what type of slider option set
|
||||
// Description: Returns the resize_thumb flag. See
|
||||
// set_resize_thumb().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGSliderBar::
|
||||
get_slider_only() const {
|
||||
return _slider_only;
|
||||
get_resize_thumb() const {
|
||||
return _resize_thumb;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_negative_mapping
|
||||
// Function: PGSliderBar::set_manage_pieces
|
||||
// Access: Published
|
||||
// Description: Sets _negative_mapping. True: slider will receive
|
||||
// _value from -1 to +1 else, _value from 0 to + 1
|
||||
// Description: Sets the manage_pieces flag. When this is true, the
|
||||
// sub-pieces of the slider bar--that is, the thumb, and
|
||||
// the left and right scroll buttons--are automatically
|
||||
// positioned and/or resized when the slider bar's
|
||||
// overall frame is changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_negative_mapping(bool value) {
|
||||
_negative_mapping = value;
|
||||
set_manage_pieces(bool manage_pieces) {
|
||||
_manage_pieces = manage_pieces;
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_negative_mapping
|
||||
// Function: PGSliderBar::get_manage_pieces
|
||||
// Access: Published
|
||||
// Description: Returns what type of value range option set
|
||||
// Description: Returns the manage_pieces flag. See
|
||||
// set_manage_pieces().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGSliderBar::
|
||||
get_negative_mapping() const {
|
||||
return _negative_mapping;
|
||||
get_manage_pieces() const {
|
||||
return _manage_pieces;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_bar_style
|
||||
// Function: PGSliderBar::set_thumb_button
|
||||
// Access: Published
|
||||
// Description: Sets the kind of frame that is drawn on top of the
|
||||
// SliderBar to represent the amount completed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_bar_style(const PGFrameStyle &style) {
|
||||
_bar_style = style;
|
||||
_bar_state = -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_bar_style
|
||||
// Access: Published
|
||||
// Description: Returns the kind of frame that is drawn on top of the
|
||||
// SliderBar to represent the amount completed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGFrameStyle PGSliderBar::
|
||||
get_bar_style() const {
|
||||
return _bar_style;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_click_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// slider button is moved
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGSliderBar::
|
||||
get_click_event() const {
|
||||
return "updated-slider-" + get_id();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_slider_button
|
||||
// Access: Published
|
||||
// Description: Returns the slider button that is drawn on the
|
||||
// SliderBar to move the slider left or right
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath PGSliderBar::
|
||||
get_slider_button() const {
|
||||
return _slider_button;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_slider_button
|
||||
// Access: Published
|
||||
// Description: sets slider button that is drawn on the
|
||||
// SliderBar to move the slider left or right
|
||||
// Description: Sets the PGButton object that will serve as the thumb
|
||||
// for this slider. This button visually represents the
|
||||
// position of the slider, and can be dragged left and
|
||||
// right by the user.
|
||||
//
|
||||
// It is the responsibility of the caller to ensure that
|
||||
// the button object is parented to the PGSliderBar
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_slider_button(NodePath &np, PGSliderButton *button) {
|
||||
_slider_button = np;
|
||||
_slider = button;
|
||||
set_thumb_button(PGButton *thumb_button) {
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->set_notify(NULL);
|
||||
}
|
||||
_thumb_button = thumb_button;
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->set_notify(this);
|
||||
}
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::clear_thumb_button
|
||||
// Access: Published
|
||||
// Description: Removes the thumb button object from control of the
|
||||
// frame. It is your responsibility to actually remove
|
||||
// or hide the button itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
clear_thumb_button() {
|
||||
set_thumb_button(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_thumb_button
|
||||
// Access: Published
|
||||
// Description: Returns the PGButton that serves as the thumb for
|
||||
// this slider, or NULL if it is not set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGButton *PGSliderBar::
|
||||
get_thumb_button() const {
|
||||
return _thumb_button;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_left_button
|
||||
// Access: Published
|
||||
// Description: Sets the PGButton object that will serve as the left
|
||||
// scroll button for this slider. This button is
|
||||
// optional; if present, the user can click on it to
|
||||
// move scroll_size units at a time to the left.
|
||||
//
|
||||
// It is the responsibility of the caller to ensure that
|
||||
// the button object is parented to the PGSliderBar
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_left_button(PGButton *left_button) {
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
_left_button->set_notify(NULL);
|
||||
}
|
||||
_left_button = left_button;
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
_left_button->set_notify(this);
|
||||
}
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::clear_left_button
|
||||
// Access: Published
|
||||
// Description: Removes the left button object from control of the
|
||||
// frame. It is your responsibility to actually remove
|
||||
// or hide the button itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
clear_left_button() {
|
||||
set_left_button(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_left_button
|
||||
// Access: Published
|
||||
// Description: Returns the left button that is drawn on left of the
|
||||
// SliderBar to move the slider left
|
||||
// Description: Returns the PGButton that serves as the left scroll
|
||||
// button for this slider, if any, or NULL if it is not
|
||||
// set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath PGSliderBar::
|
||||
INLINE PGButton *PGSliderBar::
|
||||
get_left_button() const {
|
||||
return _left_button;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::set_right_button
|
||||
// Access: Published
|
||||
// Description: Sets the PGButton object that will serve as the right
|
||||
// scroll button for this slider. This button is
|
||||
// optional; if present, the user can click on it to
|
||||
// move scroll_size units at a time to the right.
|
||||
//
|
||||
// It is the responsibility of the caller to ensure that
|
||||
// the button object is parented to the PGSliderBar
|
||||
// node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
set_right_button(PGButton *right_button) {
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
_right_button->set_notify(NULL);
|
||||
}
|
||||
_right_button = right_button;
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
_right_button->set_notify(this);
|
||||
}
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::clear_right_button
|
||||
// Access: Published
|
||||
// Description: Removes the right button object from control of the
|
||||
// frame. It is your responsibility to actually remove
|
||||
// or hide the button itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGSliderBar::
|
||||
clear_right_button() {
|
||||
set_right_button(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_right_button
|
||||
// Access: Published
|
||||
// Description: Returns the right button that is drawn on right of the
|
||||
// SliderBar to move the slider right
|
||||
// Description: Returns the PGButton that serves as the right scroll
|
||||
// button for this slider, if any, or NULL if it is not
|
||||
// set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NodePath PGSliderBar::
|
||||
INLINE PGButton *PGSliderBar::
|
||||
get_right_button() const {
|
||||
return _right_button;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_adjust_prefix
|
||||
// Access: Published, Static
|
||||
// Description: Returns the prefix that is used to define the adjust
|
||||
// event for all PGSliderBars. The adjust event is the
|
||||
// concatenation of this string followed by get_id().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGSliderBar::
|
||||
get_adjust_prefix() {
|
||||
return "adjust-";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::get_adjust_event
|
||||
// Access: Published
|
||||
// Description: Returns the event name that will be thrown when the
|
||||
// slider bar value is adjusted by the user or
|
||||
// programmatically.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE string PGSliderBar::
|
||||
get_adjust_event() const {
|
||||
return get_adjust_prefix() + get_id();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@
|
|||
|
||||
#include "pgSliderBar.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
|
||||
#include "clockObject.h"
|
||||
#include "throw_event.h"
|
||||
#include "config_pgui.h"
|
||||
#include "throw_event.h"
|
||||
#include "transformState.h"
|
||||
#include "mouseButton.h"
|
||||
|
||||
TypeHandle PGSliderBar::_type_handle;
|
||||
|
||||
|
|
@ -29,26 +33,26 @@ TypeHandle PGSliderBar::_type_handle;
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGSliderBar::
|
||||
PGSliderBar(const string &name) :
|
||||
PGItem(name),
|
||||
// _slider("slider"),
|
||||
_left("left"),
|
||||
_right("right")
|
||||
PGSliderBar(const string &name)
|
||||
: PGItem(name)
|
||||
{
|
||||
_slider = NULL;
|
||||
_range = 100.0;
|
||||
// _value is a range from (-1 to +1) that represents slider
|
||||
_value = 0.0;
|
||||
// _mapped_value is a mapping of (-1<->1) into (0<->1)
|
||||
_mapped_value = 0.5*_value + 0.5;
|
||||
// _update_x is mapping of _mapped_value wrt slider width
|
||||
_update_x = 0.0; //will be set when _width is defined
|
||||
_speed = 0.05;
|
||||
_scale = 0.05;
|
||||
_bar_state = -1;
|
||||
_update_slider = false;
|
||||
_slider_only = true;
|
||||
_negative_mapping = false;
|
||||
_min_value = 0.0f;
|
||||
_max_value = 1.0f;
|
||||
set_scroll_size(0.01f);
|
||||
set_page_size(0.1f);
|
||||
_ratio = 0.0f;
|
||||
_resize_thumb = false;
|
||||
_manage_pieces = false;
|
||||
_axis.set(1.0f, 0.0f, 0.0f);
|
||||
_needs_remanage = false;
|
||||
_needs_recompute = true;
|
||||
_needs_reposition = false;
|
||||
_scroll_button_held = NULL;
|
||||
_mouse_button_page = false;
|
||||
_dragging = false;
|
||||
_thumb_width = 0.1f;
|
||||
|
||||
set_active(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -68,14 +72,22 @@ PGSliderBar::
|
|||
PGSliderBar::
|
||||
PGSliderBar(const PGSliderBar ©) :
|
||||
PGItem(copy),
|
||||
_value(copy._value),
|
||||
_range(copy._range),
|
||||
// _slider(copy._slider),
|
||||
_left(copy._left),
|
||||
_right(copy._right)
|
||||
_min_value(copy._min_value),
|
||||
_max_value(copy._max_value),
|
||||
_scroll_value(copy._scroll_value),
|
||||
_scroll_ratio(copy._scroll_ratio),
|
||||
_page_value(copy._page_value),
|
||||
_page_ratio(copy._page_ratio),
|
||||
_ratio(copy._ratio),
|
||||
_resize_thumb(copy._resize_thumb),
|
||||
_manage_pieces(copy._manage_pieces),
|
||||
_axis(copy._axis)
|
||||
{
|
||||
_bar_state = -1;
|
||||
_slider = NULL;
|
||||
_needs_remanage = false;
|
||||
_needs_recompute = true;
|
||||
_scroll_button_held = NULL;
|
||||
_mouse_button_page = false;
|
||||
_dragging = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -91,6 +103,71 @@ make_copy() const {
|
|||
return new PGSliderBar(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::press
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button is depressed while the mouse
|
||||
// is within the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (param.has_mouse()) {
|
||||
_mouse_pos = param.get_mouse();
|
||||
}
|
||||
if (get_active() && param.get_button() == MouseButton::one()) {
|
||||
if (_needs_recompute) {
|
||||
recompute();
|
||||
}
|
||||
|
||||
if (_range_x != 0.0f) {
|
||||
_mouse_button_page = true;
|
||||
_scroll_button_held = NULL;
|
||||
advance_page();
|
||||
_next_advance_time =
|
||||
ClockObject::get_global_clock()->get_frame_time() + scroll_initial_delay;
|
||||
}
|
||||
}
|
||||
PGItem::press(param, background);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::release
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button previously depressed with
|
||||
// press() is released.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
release(const MouseWatcherParameter ¶m, bool background) {
|
||||
if (MouseButton::is_mouse_button(param.get_button())) {
|
||||
_mouse_button_page = false;
|
||||
}
|
||||
if (_dragging) {
|
||||
end_drag();
|
||||
}
|
||||
PGItem::release(param, background);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::move
|
||||
// Access: Protected, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse is moved while within the region.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
move(const MouseWatcherParameter ¶m) {
|
||||
_mouse_pos = param.get_mouse();
|
||||
if (_dragging) {
|
||||
// We only get here if we the user originally clicked on the
|
||||
// track, which caused the slider to move all the way to the mouse
|
||||
// position, and then started dragging the mouse along the track.
|
||||
// In this case, we start moving the thumb as if the user had
|
||||
// started by dragging the thumb directly.
|
||||
continue_drag();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::has_cull_callback
|
||||
// Access: Protected, Virtual
|
||||
|
|
@ -126,161 +203,599 @@ has_cull_callback() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PGSliderBar::
|
||||
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
||||
update();
|
||||
if (_manage_pieces && _needs_remanage) {
|
||||
remanage();
|
||||
}
|
||||
if (_needs_recompute) {
|
||||
recompute();
|
||||
}
|
||||
|
||||
if (_scroll_button_held != (PGItem *)NULL &&
|
||||
_next_advance_time <= ClockObject::get_global_clock()->get_frame_time()) {
|
||||
advance_scroll();
|
||||
}
|
||||
|
||||
if (_mouse_button_page &&
|
||||
_next_advance_time <= ClockObject::get_global_clock()->get_frame_time()) {
|
||||
advance_page();
|
||||
}
|
||||
|
||||
if (_needs_reposition) {
|
||||
reposition();
|
||||
}
|
||||
|
||||
return PGItem::cull_callback(trav, data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::setup
|
||||
// Access: Public
|
||||
// Description: Creates a PGSliderBar with the indicated dimensions,
|
||||
// with the indicated maximum range.
|
||||
// Function: PGSliderBar::xform
|
||||
// Access: Public, Virtual
|
||||
// Description: Transforms the contents of this node by the indicated
|
||||
// matrix, if it means anything to do so. For most
|
||||
// kinds of nodes, this does nothing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
setup(float width, float height, float range) {
|
||||
//set_state(0);
|
||||
//clear_state_def(0);
|
||||
xform(const LMatrix4f &mat) {
|
||||
PGItem::xform(mat);
|
||||
_axis = _axis * mat;
|
||||
|
||||
_width = 0.5 * width; // quick reference to find the left and right max points
|
||||
//set_frame(-0.5f * width, 0.5f * width, -0.5f * height, 0.5f * height);
|
||||
set_range(range);
|
||||
|
||||
NodePath current = NodePath(this);
|
||||
if (!_slider) {
|
||||
_slider = new PGSliderButton("slider");
|
||||
_slider_button = current.attach_new_node(_slider);
|
||||
// Make sure we set the thumb to identity position first, so it
|
||||
// won't be accidentally flattened.
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->clear_transform();
|
||||
}
|
||||
|
||||
_slider->set_slider_bar(this);
|
||||
//_slider->setup(_slider->get_name());
|
||||
_slider->setup("");
|
||||
_slider->set_drag_n_drop(true);
|
||||
_slider->set_frame(-1,1,-1.5,1.5);
|
||||
_slider_button.set_scale(_scale);
|
||||
_slider_button.set_pos(0, 0, 0); // center it
|
||||
|
||||
// if left or right button to control slider desired, create them
|
||||
if (!_slider_only) {
|
||||
_left_button = current.attach_new_node(&_left);
|
||||
_left.set_slider_bar(this);
|
||||
_right_button = current.attach_new_node(&_right);
|
||||
_right.set_slider_bar(this);
|
||||
_left.setup(_left.get_name());
|
||||
_right.setup(_right.get_name());
|
||||
_left_button.set_scale(0.5);
|
||||
_left_button.set_pos(-(_width+1), 0, -0.25);
|
||||
_right_button.set_scale(0.5);
|
||||
_right_button.set_pos((_width+0.5), 0, -0.25);
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::adjust
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// slider value is adjusted by the user or
|
||||
// programmatically.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
adjust() {
|
||||
string event = get_adjust_event();
|
||||
play_sound(event);
|
||||
throw_event(event);
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->slider_bar_adjust(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::setup_scroll_bar
|
||||
// Access: Published
|
||||
// Description: Creates PGSliderBar that represents a vertical or
|
||||
// horizontal scroll bar (if vertical is true or false,
|
||||
// respectively), with additional buttons for scrolling,
|
||||
// and a range of 0 .. 1.
|
||||
//
|
||||
// length here is the measurement along the scroll bar,
|
||||
// and width is the measurement across the scroll bar,
|
||||
// whether it is vertical or horizontal (so for a
|
||||
// horizontal scroll bar, the length is actually the x
|
||||
// dimension, and the width is the y dimension).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
setup_scroll_bar(bool vertical, float length, float width, float bevel) {
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
if (vertical) {
|
||||
set_frame(-width / 2.0f, width / 2.0f, -length / 2.0f, length / 2.0f);
|
||||
_axis = LVector3f::rfu(0.0f, 0.0f, -1.0f);
|
||||
} else {
|
||||
set_frame(-length / 2.0f, length / 2.0f, -width / 2.0f, width / 2.0f);
|
||||
_axis = LVector3f::rfu(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_width(0.3f, 0.3f);
|
||||
|
||||
/*
|
||||
style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
|
||||
style.set_type(PGFrameStyle::T_bevel_in);
|
||||
//set_frame_style(0, style);
|
||||
*/
|
||||
style.set_type(PGFrameStyle::T_flat);
|
||||
set_frame_style(0, style);
|
||||
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
style.set_type(PGFrameStyle::T_bevel_out);
|
||||
_slider->set_frame_style(PGButton::S_ready, style);
|
||||
style.set_type(PGFrameStyle::T_bevel_in);
|
||||
_slider->set_frame_style(PGButton::S_depressed, style);
|
||||
style.set_width(bevel, bevel);
|
||||
|
||||
// Remove the button nodes created by a previous call to setup(), if
|
||||
// any.
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
remove_child(_thumb_button);
|
||||
set_thumb_button(NULL);
|
||||
}
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
remove_child(_left_button);
|
||||
set_left_button(NULL);
|
||||
}
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
remove_child(_right_button);
|
||||
set_right_button(NULL);
|
||||
}
|
||||
|
||||
PT(PGButton) thumb = new PGButton("thumb");
|
||||
thumb->setup("", bevel);
|
||||
thumb->set_frame(-width / 2.0f, width / 2.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
add_child(thumb);
|
||||
set_thumb_button(thumb);
|
||||
|
||||
PT(PGButton) left = new PGButton("left");
|
||||
left->setup("", bevel);
|
||||
left->set_frame(-width / 2.0f, width / 2.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
left->set_transform(TransformState::make_pos(((width - length) / 2.0f) * _axis));
|
||||
add_child(left);
|
||||
set_left_button(left);
|
||||
|
||||
PT(PGButton) right = new PGButton("right");
|
||||
right->setup("", bevel);
|
||||
right->set_frame(-width / 2.0f, width / 2.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
right->set_transform(TransformState::make_pos(((length - width) / 2.0f) * _axis));
|
||||
add_child(right);
|
||||
set_right_button(right);
|
||||
|
||||
set_resize_thumb(true);
|
||||
set_manage_pieces(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::press
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever a
|
||||
// mouse or keyboard button is depressed while the mouse
|
||||
// is within the region.
|
||||
// Function: PGSliderBar::setup_slider
|
||||
// Access: Published
|
||||
// Description: Creates PGSliderBar that represents a slider that the
|
||||
// user can use to control an analog quantity.
|
||||
//
|
||||
// This is functionally the same as a scroll bar, but it
|
||||
// has a distinctive look.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
press(const MouseWatcherParameter ¶m, bool background) {
|
||||
PGItem::press(param, background);
|
||||
//pgui_cat.info() << get_name() << "::" << param << endl;
|
||||
//pgui_cat.info() << _slider->get_name() << "::press:x" << _slider_button.get_x()
|
||||
// << " press:y" << _slider_button.get_y() << endl;
|
||||
setup_slider(bool vertical, float length, float width, float bevel) {
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
// translate the mouse param position into frame space
|
||||
LPoint2f mouse_point = param.get_mouse();
|
||||
LVector3f result(mouse_point[0], mouse_point[1], 0);
|
||||
result = get_frame_inv_xform().xform_point(result);
|
||||
_update_slider = true;
|
||||
_update_x = result[0];
|
||||
_update_y = result[1];
|
||||
//_slider_button.set_x(result[0]);
|
||||
if (vertical) {
|
||||
set_frame(-width / 2.0f, width / 2.0f, -length / 2.0f, length / 2.0f);
|
||||
_axis = LVector3f::rfu(0.0f, 0.0f, -1.0f);
|
||||
} else {
|
||||
set_frame(-length / 2.0f, length / 2.0f, -width / 2.0f, width / 2.0f);
|
||||
_axis = LVector3f::rfu(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
|
||||
style.set_type(PGFrameStyle::T_flat);
|
||||
style.set_visible_scale(1.0f, 0.25f);
|
||||
style.set_width(bevel, bevel);
|
||||
set_frame_style(0, style);
|
||||
|
||||
// Remove the button nodes created by a previous call to setup(), if
|
||||
// any.
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
remove_child(_thumb_button);
|
||||
set_thumb_button(NULL);
|
||||
}
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
remove_child(_left_button);
|
||||
set_left_button(NULL);
|
||||
}
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
remove_child(_right_button);
|
||||
set_right_button(NULL);
|
||||
}
|
||||
|
||||
PT(PGButton) thumb = new PGButton("thumb");
|
||||
thumb->setup(" ", bevel);
|
||||
thumb->set_frame(-width / 4.0f, width / 4.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
add_child(thumb);
|
||||
set_thumb_button(thumb);
|
||||
|
||||
set_resize_thumb(false);
|
||||
set_manage_pieces(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::drag
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a hook function, called when the user
|
||||
// is trying to drag the slider button
|
||||
// Function: PGSliderBar::set_active
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets whether the PGItem is active for mouse watching.
|
||||
// This is not necessarily related to the
|
||||
// active/inactive appearance of the item, which is
|
||||
// controlled by set_state(), but it does affect whether
|
||||
// it responds to mouse events.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
drag(const MouseWatcherParameter ¶m) {
|
||||
//pgui_cat.info() << get_name() << "::" << param << endl;
|
||||
//pgui_cat.info() << _slider->get_name() << "::drag:x" << _slider_button.get_x()
|
||||
// <<" drag:y" << _slider_button.get_y() << endl;
|
||||
set_active(bool active) {
|
||||
PGItem::set_active(active);
|
||||
|
||||
// translate the mouse param position into frame space
|
||||
LPoint2f mouse_point = param.get_mouse();
|
||||
LVector3f result(mouse_point[0], mouse_point[1], 0);
|
||||
result = get_frame_inv_xform().xform_point(result);
|
||||
// keep the slider button within slider bar
|
||||
if (result[0] < -_width)
|
||||
result[0] = -_width;
|
||||
if (result[0] > _width)
|
||||
result[0] = _width;
|
||||
_update_slider = true;
|
||||
_update_x = result[0];
|
||||
_update_y = result[1];
|
||||
//_slider_button.set_x(result[0]);
|
||||
// This also implicitly sets the managed pieces.
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->set_active(active);
|
||||
}
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
_left_button->set_active(active);
|
||||
}
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
_right_button->set_active(active);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::update
|
||||
// Access: Private
|
||||
// Description: Computes the appropriate size of the bar frame
|
||||
// according to the percentage completed.
|
||||
// Function: PGSliderBar::remanage
|
||||
// Access: Published
|
||||
// Description: Manages the position and size of the scroll bars and
|
||||
// the thumb. Normally this should not need to be
|
||||
// called directly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
update() {
|
||||
// int state = get_state();
|
||||
void PGSliderBar::
|
||||
remanage() {
|
||||
_needs_remanage = false;
|
||||
|
||||
// need left and right button input if they exist
|
||||
if (!_slider_only) {
|
||||
// Handle left and right button presses
|
||||
if (_left.is_button_down()) {
|
||||
// move the slider to the left
|
||||
float x = _slider_button.get_x() - _speed;
|
||||
_update_slider = true;
|
||||
_update_x = max(x, -_width);
|
||||
//_slider_button.set_x(max(x, -_width));
|
||||
}
|
||||
const LVecBase4f &frame = get_frame();
|
||||
|
||||
float width, length;
|
||||
if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
|
||||
// The slider is X-dominant.
|
||||
width = frame[3] - frame[2];
|
||||
length = frame[1] - frame[0];
|
||||
|
||||
if (_right.is_button_down()) {
|
||||
// move the slider to the right
|
||||
float x = _slider_button.get_x() + _speed;
|
||||
_update_slider = true;
|
||||
_update_x = min(x, _width);
|
||||
//_slider_button.set_x(min(x, _width));
|
||||
}
|
||||
} else {
|
||||
// The slider is Y-dominant.
|
||||
width = frame[1] - frame[0];
|
||||
length = frame[3] - frame[2];
|
||||
}
|
||||
|
||||
// press() and drag() update schedules this values that need to be
|
||||
// applied here so that value of current slider position as a ratio
|
||||
// of range can be updated
|
||||
if (_update_slider) {
|
||||
//pgui_cat.info() << "mouse_point:x " << _update_x
|
||||
// << " mouse_point:y " << _update_y << endl;
|
||||
if (!_slider_button.is_empty())
|
||||
_slider_button.set_x(_update_x);
|
||||
_mapped_value = (_update_x + _width)/(2*_width);
|
||||
_value = _negative_mapping ? ((_mapped_value-0.5)*2) : _mapped_value;
|
||||
_update_slider = false;
|
||||
throw_event(get_click_event());
|
||||
LVector3f center = LVector3f::rfu((frame[0] + frame[1]) / 2.0f,
|
||||
0.0f,
|
||||
(frame[2] + frame[3]) / 2.0f);
|
||||
|
||||
if (_left_button != (PGButton *)NULL) {
|
||||
_left_button->set_frame(-width / 2.0f, width / 2.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
_left_button->xform(LMatrix4f::translate_mat(center + ((width - length) / 2.0f) * _axis));
|
||||
_left_button->clear_transform();
|
||||
}
|
||||
|
||||
if (_right_button != (PGButton *)NULL) {
|
||||
_right_button->set_frame(-width / 2.0f, width / 2.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
_right_button->xform(LMatrix4f::translate_mat(center + ((length - width) / 2.0f) * _axis));
|
||||
_right_button->clear_transform();
|
||||
}
|
||||
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->set_frame(-width / 2.0f, width / 2.0f,
|
||||
-width / 2.0f, width / 2.0f);
|
||||
_thumb_button->set_transform(TransformState::make_pos(center));
|
||||
}
|
||||
|
||||
recompute();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::recompute
|
||||
// Access: Published
|
||||
// Description: Recomputes the position and size of the thumb.
|
||||
// Normally this should not need to be called directly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
recompute() {
|
||||
_needs_recompute = false;
|
||||
|
||||
if (_min_value != _max_value) {
|
||||
_scroll_ratio = fabs(_scroll_value / (_max_value - _min_value));
|
||||
_page_ratio = fabs(_page_value / (_max_value - _min_value));
|
||||
|
||||
} else {
|
||||
_scroll_ratio = 0.0f;
|
||||
_page_ratio = 0.0f;
|
||||
}
|
||||
|
||||
LVecBase4f frame = get_frame();
|
||||
reduce_region(frame, _left_button);
|
||||
reduce_region(frame, _right_button);
|
||||
|
||||
if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) {
|
||||
// The slider is X-dominant.
|
||||
|
||||
_min_x = frame[0];
|
||||
_max_x = frame[1];
|
||||
|
||||
float trough_width = _max_x - _min_x;
|
||||
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
|
||||
if (_resize_thumb) {
|
||||
// If we're allowed to adjust the thumb's size, we don't need to
|
||||
// find out how wide it is.
|
||||
_thumb_width = trough_width * min(1.0f, _page_ratio);
|
||||
_thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f,
|
||||
thumb_frame[2], thumb_frame[3]);
|
||||
} else {
|
||||
// If we're not adjusting the thumb's size, we do need to know
|
||||
// its current width.
|
||||
_thumb_width = thumb_frame[1] - thumb_frame[0];
|
||||
}
|
||||
}
|
||||
|
||||
_range_x = trough_width - _thumb_width;
|
||||
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
if (_axis[0] >= 0.0f) {
|
||||
// The slider runs forwards, left to right.
|
||||
_thumb_start = (_min_x - thumb_frame[0]) * _axis;
|
||||
} else {
|
||||
// The slider runs backwards: right to left.
|
||||
_thumb_start = (thumb_frame[1] - _max_x) * _axis;
|
||||
}
|
||||
_thumb_start += LVector3f::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f);
|
||||
|
||||
} else {
|
||||
// The slider is Y-dominant. We call it X in the variable names,
|
||||
// but it's really Y (or even Z).
|
||||
|
||||
_min_x = frame[2];
|
||||
_max_x = frame[3];
|
||||
|
||||
float trough_width = _max_x - _min_x;
|
||||
|
||||
if (_thumb_button == (PGButton *)NULL) {
|
||||
_thumb_width = 0.0f;
|
||||
_range_x = 0.0f;
|
||||
_thumb_start.set(0.0f, 0.0f, 0.0f);
|
||||
|
||||
} else {
|
||||
const LVecBase4f &thumb_frame = _thumb_button->get_frame();
|
||||
|
||||
if (_resize_thumb) {
|
||||
// If we're allowed to adjust the thumb's size, we don't need to
|
||||
// find out how wide it is.
|
||||
_thumb_width = trough_width * min(1.0f, _page_ratio);
|
||||
_thumb_button->set_frame(thumb_frame[0], thumb_frame[1],
|
||||
-_thumb_width / 2.0f, _thumb_width / 2.0f);
|
||||
} else {
|
||||
// If we're not adjusting the thumb's size, we do need to know
|
||||
// its current width.
|
||||
_thumb_width = thumb_frame[3] - thumb_frame[2];
|
||||
}
|
||||
|
||||
_range_x = trough_width - _thumb_width;
|
||||
|
||||
if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) {
|
||||
// The slider runs forwards, bottom to top.
|
||||
_thumb_start = (_min_x - thumb_frame[2]) * _axis;
|
||||
} else {
|
||||
// The slider runs backwards: top to bottom.
|
||||
_thumb_start = (thumb_frame[3] - _max_x) * _axis;
|
||||
}
|
||||
_thumb_start += LVector3f::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
reposition();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when the user changes the frame size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
frame_changed() {
|
||||
PGItem::frame_changed();
|
||||
_needs_remanage = true;
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::item_transform_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's local transform
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_transform_changed(PGItem *) {
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::item_frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's frame
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_frame_changed(PGItem *) {
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::item_draw_mask_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGItem's draw_mask
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_draw_mask_changed(PGItem *) {
|
||||
_needs_recompute = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::item_press
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "press" event is triggered on a
|
||||
// watched PGItem. See PGItem::press().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_press(PGItem *item, const MouseWatcherParameter ¶m) {
|
||||
if (param.has_mouse()) {
|
||||
_mouse_pos = param.get_mouse();
|
||||
}
|
||||
if (item == _left_button || item == _right_button) {
|
||||
_scroll_button_held = item;
|
||||
_mouse_button_page = false;
|
||||
advance_scroll();
|
||||
_next_advance_time =
|
||||
ClockObject::get_global_clock()->get_frame_time() + scroll_initial_delay;
|
||||
|
||||
} else if (item == _thumb_button) {
|
||||
_scroll_button_held = NULL;
|
||||
begin_drag();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::item_release
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "release" event is triggered on a
|
||||
// watched PGItem. See PGItem::release().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_release(PGItem *item, const MouseWatcherParameter &) {
|
||||
if (item == _scroll_button_held) {
|
||||
_scroll_button_held = NULL;
|
||||
|
||||
} else if (item == _thumb_button) {
|
||||
_scroll_button_held = NULL;
|
||||
if (_dragging) {
|
||||
end_drag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::item_move
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever the "move" event is triggered on a
|
||||
// watched PGItem. See PGItem::move().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
item_move(PGItem *item, const MouseWatcherParameter ¶m) {
|
||||
_mouse_pos = param.get_mouse();
|
||||
if (item == _thumb_button) {
|
||||
if (_dragging) {
|
||||
continue_drag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::reposition
|
||||
// Access: Private
|
||||
// Description: A lighter-weight version of recompute(), this just
|
||||
// moves the thumb, assuming all other properties are
|
||||
// unchanged.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
reposition() {
|
||||
_needs_reposition = false;
|
||||
|
||||
float t = get_ratio();
|
||||
|
||||
if (_thumb_button != (PGButton *)NULL) {
|
||||
_thumb_button->set_transform(TransformState::make_pos((t * _range_x) * _axis + _thumb_start));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::advance_scroll
|
||||
// Access: Private
|
||||
// Description: Advances the scroll bar by one unit in the left or
|
||||
// right direction while the user is holding down the
|
||||
// left or right scroll button.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
advance_scroll() {
|
||||
if (_scroll_button_held == _left_button) {
|
||||
set_ratio(max(_ratio - _scroll_ratio, 0.0f));
|
||||
|
||||
} else if (_scroll_button_held == _right_button) {
|
||||
set_ratio(min(_ratio + _scroll_ratio, 1.0f));
|
||||
}
|
||||
|
||||
_next_advance_time =
|
||||
ClockObject::get_global_clock()->get_frame_time() + scroll_continued_delay;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::advance_page
|
||||
// Access: Private
|
||||
// Description: Advances the scroll bar by one page in the left or
|
||||
// right direction while the user is holding down the
|
||||
// mouse button on the track.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
advance_page() {
|
||||
// Is the mouse position left or right of the current thumb
|
||||
// position?
|
||||
LPoint3f mouse = mouse_to_local(_mouse_pos) - _thumb_start;
|
||||
float target_ratio = mouse.dot(_axis) / _range_x;
|
||||
|
||||
float t;
|
||||
if (target_ratio < _ratio) {
|
||||
t = max(_ratio - _page_ratio + _scroll_ratio, target_ratio);
|
||||
|
||||
} else {
|
||||
t = min(_ratio + _page_ratio - _scroll_ratio, target_ratio);
|
||||
}
|
||||
set_ratio(t);
|
||||
if (t == target_ratio) {
|
||||
// We made it; begin dragging from now on until the user releases
|
||||
// the mouse.
|
||||
begin_drag();
|
||||
}
|
||||
|
||||
_next_advance_time =
|
||||
ClockObject::get_global_clock()->get_frame_time() + scroll_continued_delay;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::begin_drag
|
||||
// Access: Private
|
||||
// Description: Called when the user clicks down on the thumb button,
|
||||
// possibly to begin dragging.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
begin_drag() {
|
||||
if (_needs_recompute) {
|
||||
recompute();
|
||||
}
|
||||
if (_range_x != 0.0f) {
|
||||
float current_x = mouse_to_local(_mouse_pos).dot(_axis);
|
||||
_drag_start_x = current_x - get_ratio() * _range_x;
|
||||
_dragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::continue_drag
|
||||
// Access: Private
|
||||
// Description: Called as the user moves the mouse while still
|
||||
// dragging on the thumb button.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
continue_drag() {
|
||||
if (_needs_recompute) {
|
||||
recompute();
|
||||
}
|
||||
if (_range_x != 0.0f) {
|
||||
float current_x = mouse_to_local(_mouse_pos).dot(_axis);
|
||||
set_ratio((current_x - _drag_start_x) / _range_x);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBar::end_drag
|
||||
// Access: Private
|
||||
// Description: Called as the user releases the mouse after dragging.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBar::
|
||||
end_drag() {
|
||||
_dragging = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,15 +22,20 @@
|
|||
#include "pandabase.h"
|
||||
|
||||
#include "pgItem.h"
|
||||
#include "pgSliderButton.h"
|
||||
#include "pgSliderBarNotify.h"
|
||||
#include "pgButtonNotify.h"
|
||||
#include "pgButton.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGSliderBar
|
||||
// Description : This is a particular kind of PGItem that draws a
|
||||
// little bar with a slider that moves from left to
|
||||
// right indicating a value between the ranges
|
||||
// right indicating a value between the ranges.
|
||||
//
|
||||
// This is used as an implementation for both
|
||||
// DirectSlider and for DirectScrollBar.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGSliderBar : public PGItem {
|
||||
class EXPCL_PANDA PGSliderBar : public PGItem, public PGButtonNotify {
|
||||
PUBLISHED:
|
||||
PGSliderBar(const string &name = "");
|
||||
virtual ~PGSliderBar();
|
||||
|
|
@ -42,71 +47,110 @@ public:
|
|||
virtual PandaNode *make_copy() const;
|
||||
virtual bool has_cull_callback() const;
|
||||
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
|
||||
virtual void xform(const LMatrix4f &mat);
|
||||
|
||||
virtual void press(const MouseWatcherParameter ¶m, bool background);
|
||||
virtual void drag(const MouseWatcherParameter ¶m);
|
||||
virtual void release(const MouseWatcherParameter ¶m, bool background);
|
||||
virtual void move(const MouseWatcherParameter ¶m);
|
||||
|
||||
virtual void adjust();
|
||||
|
||||
INLINE void set_notify(PGSliderBarNotify *notify);
|
||||
INLINE PGSliderBarNotify *get_notify() const;
|
||||
|
||||
PUBLISHED:
|
||||
void setup(float width, float height, float range);
|
||||
void setup_scroll_bar(bool vertical, float length, float width, float bevel);
|
||||
void setup_slider(bool vertical, float length, float width, float bevel);
|
||||
|
||||
INLINE void set_range(float range);
|
||||
INLINE float get_range() const;
|
||||
INLINE void set_axis(const LVector3f &axis);
|
||||
INLINE const LVector3f &get_axis() const;
|
||||
|
||||
//INLINE void set_magnifier(float value);
|
||||
//INLINE float get_magnifier() const;
|
||||
INLINE void set_range(float min_value, float max_value);
|
||||
INLINE float get_min_value() const;
|
||||
INLINE float get_max_value() const;
|
||||
|
||||
INLINE void set_scroll_size(float scroll_size);
|
||||
INLINE float get_scroll_size() const;
|
||||
|
||||
INLINE void set_page_size(float page_size);
|
||||
INLINE float get_page_size() const;
|
||||
|
||||
INLINE void set_value(float value);
|
||||
INLINE float get_value() const;
|
||||
INLINE float get_mapped_value() const;
|
||||
INLINE float get_update_x() const;
|
||||
INLINE float get_update_y() const;
|
||||
|
||||
INLINE void set_speed(float speed);
|
||||
INLINE float get_speed() const;
|
||||
INLINE void set_ratio(float ratio);
|
||||
INLINE float get_ratio() const;
|
||||
|
||||
INLINE void set_scale(float speed);
|
||||
INLINE float get_scale() const;
|
||||
INLINE void set_resize_thumb(bool resize_thumb);
|
||||
INLINE bool get_resize_thumb() const;
|
||||
|
||||
INLINE void set_slider_only(bool value);
|
||||
INLINE bool get_slider_only() const ;
|
||||
INLINE void set_negative_mapping(bool value);
|
||||
INLINE bool get_negative_mapping() const ;
|
||||
INLINE void set_manage_pieces(bool manage_pieces);
|
||||
INLINE bool get_manage_pieces() const;
|
||||
|
||||
INLINE void set_bar_style(const PGFrameStyle &style);
|
||||
INLINE PGFrameStyle get_bar_style() const;
|
||||
INLINE string get_click_event() const;
|
||||
INLINE void set_thumb_button(PGButton *thumb_button);
|
||||
INLINE void clear_thumb_button();
|
||||
INLINE PGButton *get_thumb_button() const;
|
||||
|
||||
INLINE void set_slider_button(NodePath &np, PGSliderButton *button);
|
||||
INLINE void set_left_button(PGButton *left_button);
|
||||
INLINE void clear_left_button();
|
||||
INLINE PGButton *get_left_button() const;
|
||||
|
||||
INLINE NodePath get_slider_button() const;
|
||||
INLINE NodePath get_left_button() const;
|
||||
INLINE NodePath get_right_button() const;
|
||||
INLINE void set_right_button(PGButton *right_button);
|
||||
INLINE void clear_right_button();
|
||||
INLINE PGButton *get_right_button() const;
|
||||
|
||||
INLINE static string get_adjust_prefix();
|
||||
INLINE string get_adjust_event() const;
|
||||
|
||||
virtual void set_active(bool active);
|
||||
|
||||
void remanage();
|
||||
void recompute();
|
||||
|
||||
protected:
|
||||
virtual void frame_changed();
|
||||
|
||||
virtual void item_transform_changed(PGItem *item);
|
||||
virtual void item_frame_changed(PGItem *item);
|
||||
virtual void item_draw_mask_changed(PGItem *item);
|
||||
virtual void item_press(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_release(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
virtual void item_move(PGItem *item, const MouseWatcherParameter ¶m);
|
||||
|
||||
private:
|
||||
void update();
|
||||
void reposition();
|
||||
void advance_scroll();
|
||||
void advance_page();
|
||||
void begin_drag();
|
||||
void continue_drag();
|
||||
void end_drag();
|
||||
|
||||
bool _slider_only;
|
||||
bool _negative_mapping;
|
||||
bool _update_slider;
|
||||
private:
|
||||
bool _needs_remanage;
|
||||
bool _needs_recompute;
|
||||
bool _needs_reposition;
|
||||
|
||||
// These 3 variables control slider range
|
||||
float _value;
|
||||
float _mapped_value;
|
||||
float _update_x;
|
||||
float _update_y;
|
||||
float _min_value, _max_value;
|
||||
float _scroll_value, _scroll_ratio;
|
||||
float _page_value, _page_ratio;
|
||||
float _ratio;
|
||||
bool _resize_thumb;
|
||||
bool _manage_pieces;
|
||||
|
||||
float _range;
|
||||
float _speed, _width;
|
||||
float _scale;
|
||||
int _bar_state;
|
||||
PGFrameStyle _bar_style;
|
||||
PGSliderButton *_slider;
|
||||
PGSliderButton _left;
|
||||
PGSliderButton _right;
|
||||
NodePath _bar;
|
||||
NodePath _slider_button;
|
||||
NodePath _left_button;
|
||||
NodePath _right_button;
|
||||
LVector3f _axis;
|
||||
|
||||
PT(PGButton) _thumb_button;
|
||||
PT(PGButton) _left_button;
|
||||
PT(PGButton) _right_button;
|
||||
|
||||
float _min_x, _max_x, _thumb_width, _range_x;
|
||||
LPoint3f _thumb_start;
|
||||
PGItem *_scroll_button_held;
|
||||
bool _mouse_button_page;
|
||||
LPoint2f _mouse_pos;
|
||||
double _next_advance_time;
|
||||
bool _dragging;
|
||||
float _drag_start_x;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Filename: pgSliderBarNotify.I
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBarNotify::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PGSliderBarNotify::
|
||||
PGSliderBarNotify() {
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// Filename: pgSliderBarNotify.cxx
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgSliderBarNotify.h"
|
||||
#include "pgSliderBar.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBarNotify::slider_bar_adjust
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGSliderBar's value
|
||||
// has been changed by the user or programmatically.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBarNotify::
|
||||
slider_bar_adjust(PGSliderBar *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderBarNotify::slider_bar_set_range
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called whenever a watched PGSliderBar's overall range
|
||||
// has been changed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderBarNotify::
|
||||
slider_bar_set_range(PGSliderBar *) {
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Filename: pgSliderBarNotify.h
|
||||
// Created by: drose (18Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGSLIDERBARNOTIFY_H
|
||||
#define PGSLIDERBARNOTIFY_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pgItemNotify.h"
|
||||
|
||||
class PGSliderBar;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGSliderBarNotify
|
||||
// Description : Objects that inherit from this class can receive
|
||||
// notify messages when a slider bar moves or otherwise
|
||||
// is reconfigured.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGSliderBarNotify : public PGItemNotify {
|
||||
public:
|
||||
INLINE PGSliderBarNotify();
|
||||
|
||||
protected:
|
||||
virtual void slider_bar_adjust(PGSliderBar *slider_bar);
|
||||
virtual void slider_bar_set_range(PGSliderBar *slider_bar);
|
||||
|
||||
friend class PGSliderBar;
|
||||
};
|
||||
|
||||
#include "pgSliderBarNotify.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Filename: pgSliderButton.cxx
|
||||
// Created by: masad (21Oct04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgSliderButton.h"
|
||||
#include "pgSliderBar.h"
|
||||
#include "dcast.h"
|
||||
#include "pgMouseWatcherParameter.h"
|
||||
|
||||
#include "throw_event.h"
|
||||
#include "mouseButton.h"
|
||||
#include "mouseWatcherParameter.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "transformState.h"
|
||||
|
||||
TypeHandle PGSliderButton::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGSliderButton::
|
||||
PGSliderButton(const string &name) : PGButton(name)
|
||||
{
|
||||
_drag_n_drop = false;
|
||||
_slider_bar = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGSliderButton::
|
||||
~PGSliderButton() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGSliderButton::
|
||||
PGSliderButton(const PGSliderButton ©) :
|
||||
PGButton(copy),
|
||||
_drag_n_drop(copy._drag_n_drop)
|
||||
// _slider_bar(copy._slider_bar)
|
||||
{
|
||||
_slider_bar = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGSliderButton::
|
||||
make_copy() const {
|
||||
return new PGSliderButton(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGSliderButton::move
|
||||
// Access: Public, Virtual
|
||||
// Description: This is a callback hook function, called whenever the
|
||||
// button is dragged left or right by the user normally.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGSliderButton::
|
||||
move(const MouseWatcherParameter ¶m) {
|
||||
PGButton::move(param);
|
||||
if (_drag_n_drop && is_button_down()) {
|
||||
PGSliderBar *slider = DCAST(PGSliderBar, _slider_bar);
|
||||
slider->drag(param);
|
||||
//pgui_cat.info() << get_name() << "::move()" << endl;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
// Filename: pgSliderButton.h
|
||||
// Created by: masad (21Oct04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGSLIDERBUTTON_H
|
||||
#define PGSLIDERBUTTON_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pgButton.h"
|
||||
#include "nodePath.h"
|
||||
#include "pset.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGSliderButton
|
||||
// Description : This is a particular kind of PGItem that is
|
||||
// specialized to behave like a normal button object.
|
||||
// It keeps track of its own state, and handles mouse
|
||||
// events sensibly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGSliderButton : public PGButton {
|
||||
PUBLISHED:
|
||||
PGSliderButton(const string &name);
|
||||
virtual ~PGSliderButton();
|
||||
|
||||
public:
|
||||
|
||||
virtual void move(const MouseWatcherParameter ¶m);
|
||||
PGSliderButton(const PGSliderButton ©);
|
||||
|
||||
PUBLISHED:
|
||||
|
||||
INLINE bool is_drag_n_drop();
|
||||
INLINE void set_drag_n_drop(bool value);
|
||||
INLINE void set_slider_bar(PGItem *item);
|
||||
|
||||
public:
|
||||
virtual PandaNode *make_copy() const;
|
||||
|
||||
bool _drag_n_drop;
|
||||
PGItem *_slider_bar;
|
||||
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PGButton::init_type();
|
||||
register_type(_type_handle, "PGSliderButton",
|
||||
PGButton::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
};
|
||||
|
||||
#include "pgSliderButton.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -42,6 +42,18 @@ get_mouse_watcher() const {
|
|||
return _watcher;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGTop::get_group
|
||||
// Access: Published
|
||||
// Description: Returns the MouseWatcherGroup pointer that the PGTop
|
||||
// object registers its PG items with, or NULL if the
|
||||
// MouseWatcher has not yet been set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MouseWatcherGroup *PGTop::
|
||||
get_group() const {
|
||||
return _watcher_group;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGTop::set_start_sort
|
||||
// Access: Published
|
||||
|
|
@ -83,15 +95,12 @@ get_start_sort() const {
|
|||
// Function: PGTop::add_region
|
||||
// Access: Public
|
||||
// Description: Adds the indicated region to the set of regions in
|
||||
// the group. Returns true if it was successfully
|
||||
// added, or false if it was already on the list.
|
||||
// the group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGTop::
|
||||
INLINE void PGTop::
|
||||
add_region(MouseWatcherRegion *region) {
|
||||
if (_watcher_group == (PGMouseWatcherGroup *)NULL) {
|
||||
return false;
|
||||
}
|
||||
return _watcher_group->add_region(region);
|
||||
nassertv(_watcher_group != (PGMouseWatcherGroup *)NULL);
|
||||
_watcher_group->add_region(region);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -60,13 +60,14 @@ public:
|
|||
PUBLISHED:
|
||||
void set_mouse_watcher(MouseWatcher *watcher);
|
||||
INLINE MouseWatcher *get_mouse_watcher() const;
|
||||
INLINE MouseWatcherGroup *get_group() const;
|
||||
|
||||
INLINE void set_start_sort(int start_sort);
|
||||
INLINE int get_start_sort() const;
|
||||
|
||||
public:
|
||||
// These methods duplicate the functionality of MouseWatcherGroup.
|
||||
INLINE bool add_region(MouseWatcherRegion *region);
|
||||
INLINE void add_region(MouseWatcherRegion *region);
|
||||
INLINE void clear_regions();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
// Filename: pgVirtualFrame.I
|
||||
// Created by: drose (17Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::set_clip_frame
|
||||
// Access: Published
|
||||
// Description: Sets the bounding rectangle of the clip frame.
|
||||
// This is the size of the small window through which we
|
||||
// can see the virtual canvas. Normally, this is the
|
||||
// same size as the actual frame or smaller (typically
|
||||
// it is smaller by the size of the bevel, or to make
|
||||
// room for scroll bars).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGVirtualFrame::
|
||||
set_clip_frame(float left, float right, float bottom, float top) {
|
||||
set_clip_frame(LVecBase4f(left, right, bottom, top));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::get_clip_frame
|
||||
// Access: Published
|
||||
// Description: Returns the bounding rectangle of the clip frame.
|
||||
// See set_clip_frame(). If has_clip_frame() is
|
||||
// false, this returns the item's actual frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase4f &PGVirtualFrame::
|
||||
get_clip_frame() const {
|
||||
return _has_clip_frame ? _clip_frame : get_frame();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::has_clip_frame
|
||||
// Access: Published
|
||||
// Description: Returns true if the clip frame has been set; see
|
||||
// set_clip_frame(). If it has not been set, objects in
|
||||
// the virtual frame will not be clipped.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PGVirtualFrame::
|
||||
has_clip_frame() const {
|
||||
return _has_clip_frame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::set_canvas_transform
|
||||
// Access: Published
|
||||
// Description: Changes the transform of the virtual canvas. This
|
||||
// transform is applied to all child nodes of the
|
||||
// canvas_node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGVirtualFrame::
|
||||
set_canvas_transform(const TransformState *transform) {
|
||||
_canvas_node->set_transform(transform);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::get_canvas_transform
|
||||
// Access: Published
|
||||
// Description: Returns the transform of the virtual canvas. This
|
||||
// transform is applied to all child nodes of the
|
||||
// canvas_node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TransformState *PGVirtualFrame::
|
||||
get_canvas_transform() const {
|
||||
return _canvas_node->get_transform();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::get_canvas_node
|
||||
// Access: Published
|
||||
// Description: Returns the special node that holds all of the
|
||||
// children that appear in the virtual canvas.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *PGVirtualFrame::
|
||||
get_canvas_node() const {
|
||||
return _canvas_node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::get_clip_plane_node
|
||||
// Access: Published
|
||||
// Description: Returns the special node that holds all of PlaneNodes
|
||||
// that are used for applying the clip planes to the
|
||||
// canvas_node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PandaNode *PGVirtualFrame::
|
||||
get_clip_plane_node() const {
|
||||
return _clip_plane_node;
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
// Filename: pgVirtualFrame.cxx
|
||||
// Created by: drose (17Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgVirtualFrame.h"
|
||||
#include "clipPlaneAttrib.h"
|
||||
#include "planeNode.h"
|
||||
#include "sceneGraphReducer.h"
|
||||
|
||||
TypeHandle PGVirtualFrame::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGVirtualFrame::
|
||||
PGVirtualFrame(const string &name) : PGItem(name)
|
||||
{
|
||||
_has_clip_frame = false;
|
||||
_clip_frame.set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
setup_child_nodes();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGVirtualFrame::
|
||||
~PGVirtualFrame() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::Copy Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGVirtualFrame::
|
||||
PGVirtualFrame(const PGVirtualFrame ©) :
|
||||
PGItem(copy),
|
||||
_has_clip_frame(copy._has_clip_frame),
|
||||
_clip_frame(copy._clip_frame)
|
||||
{
|
||||
setup_child_nodes();
|
||||
|
||||
// Reassign the clip planes according to the clip frame.
|
||||
if (_has_clip_frame) {
|
||||
set_clip_frame(_clip_frame);
|
||||
} else {
|
||||
clear_clip_frame();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated Node that is a shallow copy
|
||||
// of this one. It will be a different Node pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original Node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PGVirtualFrame::
|
||||
make_copy() const {
|
||||
return new PGVirtualFrame(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::r_copy_children
|
||||
// Access: Protected, Virtual
|
||||
// Description: This is called by r_copy_subgraph(); the copy has
|
||||
// already been made of this particular node (and this
|
||||
// is the copy); this function's job is to copy all of
|
||||
// the children from the original.
|
||||
//
|
||||
// Note that it includes the parameter inst_map, which
|
||||
// is a map type, and is not (and cannot be) exported
|
||||
// from PANDA.DLL. Thus, any derivative of PandaNode
|
||||
// that is not also a member of PANDA.DLL *cannot*
|
||||
// access this map, and probably should not even
|
||||
// override this function.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) {
|
||||
PandaNode::r_copy_children(from, inst_map);
|
||||
|
||||
// Reassign the canvas_node to point to the new copy, if it's there.
|
||||
const PGVirtualFrame *from_frame = DCAST(PGVirtualFrame, from);
|
||||
PandaNode *from_canvas_node = from_frame->get_canvas_node();
|
||||
PandaNode *from_clip_plane_node = from_frame->get_clip_plane_node();
|
||||
|
||||
InstanceMap::const_iterator ci;
|
||||
ci = inst_map.find(from_canvas_node);
|
||||
if (ci != inst_map.end()) {
|
||||
remove_child(_canvas_node);
|
||||
_canvas_node = DCAST(ModelNode, (*ci).second);
|
||||
}
|
||||
|
||||
ci = inst_map.find(from_clip_plane_node);
|
||||
if (ci != inst_map.end()) {
|
||||
remove_child(_clip_plane_node);
|
||||
_clip_plane_node = (*ci).second;
|
||||
}
|
||||
|
||||
// Reassign the clip planes according to the clip frame.
|
||||
if (_has_clip_frame) {
|
||||
set_clip_frame(_clip_frame);
|
||||
} else {
|
||||
clear_clip_frame();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::setup
|
||||
// Access: Published
|
||||
// Description: Creates a PGVirtualFrame with the indicated
|
||||
// dimensions.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
setup(float width, float height) {
|
||||
set_state(0);
|
||||
clear_state_def(0);
|
||||
|
||||
set_frame(0, width, 0, height);
|
||||
|
||||
float bevel = 0.05f;
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_width(bevel, bevel);
|
||||
|
||||
style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
style.set_type(PGFrameStyle::T_bevel_out);
|
||||
set_frame_style(0, style);
|
||||
|
||||
set_clip_frame(bevel, width - 2 * bevel,
|
||||
bevel, height - 2 * bevel);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::set_clip_frame
|
||||
// Access: Published
|
||||
// Description: Sets the bounding rectangle of the clip frame.
|
||||
// This is the size of the small window through which we
|
||||
// can see the virtual canvas. Normally, this is the
|
||||
// same size as the actual frame or smaller (typically
|
||||
// it is smaller by the size of the bevel, or to make
|
||||
// room for scroll bars).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
set_clip_frame(const LVecBase4f &frame) {
|
||||
if (!_has_clip_frame || _clip_frame != frame) {
|
||||
_has_clip_frame = true;
|
||||
_clip_frame = frame;
|
||||
|
||||
const LVector3f r = LVector3f::right();
|
||||
const LVector3f u = LVector3f::up();
|
||||
|
||||
PT(PlaneNode) left_clip =
|
||||
new PlaneNode("left_clip", Planef(r, r * _clip_frame[0]));
|
||||
PT(PlaneNode) right_clip =
|
||||
new PlaneNode("right_clip", Planef(-r, r * _clip_frame[1]));
|
||||
|
||||
PT(PlaneNode) bottom_clip =
|
||||
new PlaneNode("bottom_clip", Planef(u, u * _clip_frame[2]));
|
||||
PT(PlaneNode) top_clip =
|
||||
new PlaneNode("top_clip", Planef(-u, u * _clip_frame[3]));
|
||||
|
||||
_clip_plane_node->remove_all_children();
|
||||
_clip_plane_node->add_child(left_clip);
|
||||
_clip_plane_node->add_child(right_clip);
|
||||
_clip_plane_node->add_child(bottom_clip);
|
||||
_clip_plane_node->add_child(top_clip);
|
||||
|
||||
CPT(ClipPlaneAttrib) plane_attrib = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
|
||||
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(left_clip)));
|
||||
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(right_clip)));
|
||||
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(bottom_clip)));
|
||||
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(top_clip)));
|
||||
|
||||
_canvas_node->set_attrib(plane_attrib);
|
||||
clip_frame_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::clear_clip_frame
|
||||
// Access: Published
|
||||
// Description: Removes the clip frame from the item. This
|
||||
// disables clipping.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
clear_clip_frame() {
|
||||
if (_has_clip_frame) {
|
||||
_has_clip_frame = false;
|
||||
|
||||
_canvas_node->clear_attrib(ClipPlaneAttrib::get_class_type());
|
||||
clip_frame_changed();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::clip_frame_changed
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when the user changes the clip_frame size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
clip_frame_changed() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGVirtualFrame::setup_child_nodes
|
||||
// Access: Private
|
||||
// Description: Creates the special canvas_node and clip_plane_node
|
||||
// for this object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PGVirtualFrame::
|
||||
setup_child_nodes() {
|
||||
_canvas_node = new ModelNode("canvas");
|
||||
_canvas_node->set_preserve_transform(ModelNode::PT_local);
|
||||
// We have to preserve the clip plane attribute.
|
||||
_canvas_node->set_preserve_attributes(SceneGraphReducer::TT_other);
|
||||
add_child(_canvas_node);
|
||||
|
||||
_clip_plane_node = new PandaNode("clip_planes");
|
||||
add_child(_clip_plane_node);
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
// Filename: pgVirtualFrame.h
|
||||
// Created by: drose (17Aug05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PGVIRTUALFRAME_H
|
||||
#define PGVIRTUALFRAME_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pgItem.h"
|
||||
#include "modelNode.h"
|
||||
|
||||
class TransformState;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGVirtualFrame
|
||||
// Description : This represents a frame that is rendered as a window
|
||||
// onto another (possibly much larger) canvas. You can
|
||||
// only see the portion of the canvas that is below the
|
||||
// window at any given time.
|
||||
//
|
||||
// This works simply by automatically defining clipping
|
||||
// planes to be applied to a special child node, called
|
||||
// the canvas_node, of the PGVirtualFrame node. Every
|
||||
// object that is parented to the canvas_node will be
|
||||
// clipped by the clip_frame. Also, you can modify the
|
||||
// canvas_transform through convenience methods here,
|
||||
// which actually modifies the transform on the
|
||||
// canvas_node.
|
||||
//
|
||||
// The net effect is that the virtual canvas is
|
||||
// arbitrarily large, and we can peek at it through the
|
||||
// clip_frame, and scroll through different parts of it
|
||||
// by modifying the canvas_transform.
|
||||
//
|
||||
// See PGScrollFrame for a specialization of this class
|
||||
// that handles the traditional scrolling canvas, with
|
||||
// scroll bars.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA PGVirtualFrame : public PGItem {
|
||||
PUBLISHED:
|
||||
PGVirtualFrame(const string &name = "");
|
||||
virtual ~PGVirtualFrame();
|
||||
|
||||
protected:
|
||||
PGVirtualFrame(const PGVirtualFrame ©);
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map);
|
||||
|
||||
PUBLISHED:
|
||||
void setup(float width, float height);
|
||||
|
||||
INLINE void set_clip_frame(float left, float right, float bottom, float top);
|
||||
void set_clip_frame(const LVecBase4f &clip_frame);
|
||||
INLINE const LVecBase4f &get_clip_frame() const;
|
||||
INLINE bool has_clip_frame() const;
|
||||
void clear_clip_frame();
|
||||
|
||||
INLINE void set_canvas_transform(const TransformState *transform);
|
||||
INLINE const TransformState *get_canvas_transform() const;
|
||||
|
||||
INLINE PandaNode *get_canvas_node() const;
|
||||
INLINE PandaNode *get_clip_plane_node() const;
|
||||
|
||||
protected:
|
||||
virtual void clip_frame_changed();
|
||||
|
||||
private:
|
||||
void setup_child_nodes();
|
||||
|
||||
private:
|
||||
bool _has_clip_frame;
|
||||
LVecBase4f _clip_frame;
|
||||
|
||||
PT(ModelNode) _canvas_node;
|
||||
PT(PandaNode) _clip_plane_node;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PGItem::init_type();
|
||||
register_type(_type_handle, "PGVirtualFrame",
|
||||
PGItem::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "pgVirtualFrame.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -113,7 +113,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PGWaitBar::setup
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Creates a PGWaitBar with the indicated dimensions,
|
||||
// with the indicated maximum range.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -124,8 +124,10 @@ setup(float width, float height, float range) {
|
|||
|
||||
set_frame(-0.5f * width, 0.5f * width, -0.5f * height, 0.5f * height);
|
||||
|
||||
float bevel = 0.05f;
|
||||
|
||||
PGFrameStyle style;
|
||||
style.set_width(0.05f, 0.05f);
|
||||
style.set_width(bevel, bevel);
|
||||
|
||||
style.set_color(0.6f, 0.6f, 0.6f, 1.0f);
|
||||
style.set_type(PGFrameStyle::T_bevel_in);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
|
||||
#include "config_pgui.cxx"
|
||||
#include "pgButton.cxx"
|
||||
#include "pgSliderButton.cxx"
|
||||
#include "pgButtonNotify.cxx"
|
||||
#include "pgCullTraverser.cxx"
|
||||
#include "pgEntry.cxx"
|
||||
#include "pgMouseWatcherGroup.cxx"
|
||||
#include "pgMouseWatcherParameter.cxx"
|
||||
|
||||
#include "pgFrameStyle.cxx"
|
||||
#include "pgItem.cxx"
|
||||
#include "pgItemNotify.cxx"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
#include "pgFrameStyle.cxx"
|
||||
#include "pgItem.cxx"
|
||||
#include "pgMouseWatcherBackground.cxx"
|
||||
#include "pgMouseWatcherRegion.cxx"
|
||||
#include "pgTop.cxx"
|
||||
#include "pgWaitBar.cxx"
|
||||
#include "pgScrollFrame.cxx"
|
||||
#include "pgSliderBar.cxx"
|
||||
#include "pgSliderBarNotify.cxx"
|
||||
#include "pgTop.cxx"
|
||||
#include "pgVirtualFrame.cxx"
|
||||
#include "pgWaitBar.cxx"
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,10 @@ static const unsigned short _bam_major_ver = 5;
|
|||
// Bumped to major version 4 on 4/10/02 to store new scene graph.
|
||||
// Bumped to major version 5 on 5/6/05 for new Geom implementation.
|
||||
|
||||
static const unsigned short _bam_minor_ver = 2;
|
||||
static const unsigned short _bam_minor_ver = 3;
|
||||
// Bumped to minor version 1 on 7/14/05 to add TextureStage::_saved_result.
|
||||
// Bumped to minor version 2 on 7/21/05 to add TransformState::is_2d.
|
||||
// Bumped to minor version 3 on 8/25/05 to add ModelNode::_preserve_attributes.
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#begin lib_target
|
||||
#define TARGET tform
|
||||
#define LOCAL_LIBS \
|
||||
dgraph pgraph linmath display event putil gobj gsgbase \
|
||||
grutil dgraph pgraph linmath display event putil gobj gsgbase \
|
||||
mathutil device
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "transformState.h"
|
||||
#include "displayRegion.h"
|
||||
#include "dcast.h"
|
||||
#include "indent.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
|
@ -122,58 +123,9 @@ get_over_region(const LPoint2f &pos) const {
|
|||
return get_preferred_region(regions);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcher::
|
||||
output(ostream &out) const {
|
||||
DataNode::output(out);
|
||||
|
||||
int count = _regions.size();
|
||||
Groups::const_iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
MouseWatcherGroup *group = (*gi);
|
||||
count += group->_regions.size();
|
||||
}
|
||||
|
||||
out << " (" << count << " regions)";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::write
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcher::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< "MouseWatcher " << get_name() << ":\n";
|
||||
Regions::const_iterator ri;
|
||||
for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
|
||||
MouseWatcherRegion *region = (*ri);
|
||||
region->write(out, indent_level + 2);
|
||||
}
|
||||
|
||||
if (!_groups.empty()) {
|
||||
Groups::const_iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
MouseWatcherGroup *group = (*gi);
|
||||
indent(out, indent_level + 2)
|
||||
<< "Subgroup:\n";
|
||||
for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
|
||||
MouseWatcherRegion *region = (*ri);
|
||||
region->write(out, indent_level + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::add_group
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Adds the indicated group of regions to the set of
|
||||
// regions the MouseWatcher will monitor each frame.
|
||||
//
|
||||
|
|
@ -207,7 +159,7 @@ add_group(MouseWatcherGroup *group) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::remove_group
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Removes the indicated group from the set of extra
|
||||
// groups associated with the MouseWatcher. Returns
|
||||
// true if successful, or false if the group was already
|
||||
|
|
@ -237,6 +189,71 @@ remove_group(MouseWatcherGroup *group) {
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::get_num_groups
|
||||
// Access: Published
|
||||
// Description: Returns the number of separate groups added to the
|
||||
// MouseWatcher via add_group().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int MouseWatcher::
|
||||
get_num_groups() const {
|
||||
return _groups.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::get_group
|
||||
// Access: Published
|
||||
// Description: Returns the nth group added to the MouseWatcher via
|
||||
// add_group().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
MouseWatcherGroup *MouseWatcher::
|
||||
get_group(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_groups.size(), NULL);
|
||||
return _groups[n];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcher::
|
||||
output(ostream &out) const {
|
||||
DataNode::output(out);
|
||||
|
||||
int count = _regions.size();
|
||||
Groups::const_iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
MouseWatcherGroup *group = (*gi);
|
||||
count += group->_regions.size();
|
||||
}
|
||||
|
||||
out << " (" << count << " regions)";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::write
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcher::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< "MouseWatcher " << get_name() << ":\n";
|
||||
MouseWatcherGroup::write(out, indent_level + 2);
|
||||
|
||||
if (!_groups.empty()) {
|
||||
Groups::const_iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
MouseWatcherGroup *group = (*gi);
|
||||
indent(out, indent_level + 2)
|
||||
<< "Subgroup:\n";
|
||||
group->write(out, indent_level + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcher::get_over_regions
|
||||
// Access: Protected
|
||||
|
|
@ -611,14 +628,14 @@ throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
|
|||
// being moved from last position.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcher::
|
||||
move(ButtonHandle button) {
|
||||
move() {
|
||||
MouseWatcherParameter param;
|
||||
param.set_button(button);
|
||||
param.set_modifier_buttons(_mods);
|
||||
param.set_mouse(_mouse);
|
||||
|
||||
if (_preferred_button_down_region != (MouseWatcherRegion *)NULL)
|
||||
if (_preferred_button_down_region != (MouseWatcherRegion *)NULL) {
|
||||
_preferred_button_down_region->move(param);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -980,7 +997,6 @@ consider_keyboard_suppress(const MouseWatcherRegion *region) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcher::
|
||||
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
|
||||
bool mouse_moved = false;
|
||||
// Initially, we do not suppress any events to objects below us in
|
||||
// the data graph.
|
||||
_internal_suppress = 0;
|
||||
|
|
@ -1002,7 +1018,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
|
|||
// Asad: determine if mouse moved from last position
|
||||
const LVecBase2f &last_f = _xy->get_value();
|
||||
if (f != last_f) {
|
||||
mouse_moved = true;
|
||||
move();
|
||||
}
|
||||
|
||||
if (_display_region != (DisplayRegion *)NULL) {
|
||||
|
|
@ -1083,10 +1099,6 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
|
|||
|
||||
if (_has_mouse &&
|
||||
(_internal_suppress & MouseWatcherRegion::SF_mouse_position) == 0) {
|
||||
if (mouse_moved) {
|
||||
move(ButtonHandle::none());
|
||||
//tform_cat.info() << "do_transmit_data()::mouse_moved" << endl;
|
||||
}
|
||||
// Transmit the mouse position.
|
||||
_xy->set_value(_mouse);
|
||||
output.set_data(_xy_output, EventParameter(_xy));
|
||||
|
|
|
|||
|
|
@ -109,13 +109,15 @@ PUBLISHED:
|
|||
INLINE DisplayRegion *get_display_region() const;
|
||||
INLINE bool has_display_region() const;
|
||||
|
||||
bool add_group(MouseWatcherGroup *group);
|
||||
bool remove_group(MouseWatcherGroup *group);
|
||||
int get_num_groups() const;
|
||||
MouseWatcherGroup *get_group(int n) const;
|
||||
|
||||
public:
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
bool add_group(MouseWatcherGroup *group);
|
||||
bool remove_group(MouseWatcherGroup *group);
|
||||
|
||||
protected:
|
||||
typedef pvector< PT(MouseWatcherRegion) > VRegions;
|
||||
void get_over_regions(VRegions ®ions, const LPoint2f &pos) const;
|
||||
|
|
@ -136,7 +138,7 @@ protected:
|
|||
const MouseWatcherRegion *region,
|
||||
const ButtonHandle &button);
|
||||
|
||||
void move(ButtonHandle button);
|
||||
void move();
|
||||
void press(ButtonHandle button);
|
||||
void release(ButtonHandle button);
|
||||
void keystroke(int keycode);
|
||||
|
|
|
|||
|
|
@ -17,10 +17,24 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "mouseWatcherGroup.h"
|
||||
|
||||
#include "lineSegs.h"
|
||||
#include "indent.h"
|
||||
|
||||
TypeHandle MouseWatcherGroup::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
MouseWatcherGroup::
|
||||
MouseWatcherGroup() {
|
||||
#ifndef NDEBUG
|
||||
_show_regions = false;
|
||||
_color.set(0.4f, 0.6f, 1.0f, 1.0f);
|
||||
#endif // NDEBUG
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::Destructor
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -34,31 +48,30 @@ MouseWatcherGroup::
|
|||
// Function: MouseWatcherGroup::add_region
|
||||
// Access: Published
|
||||
// Description: Adds the indicated region to the set of regions in
|
||||
// the group. Returns true if it was successfully
|
||||
// added, or false if it was already on the list.
|
||||
// the group. It is an error to add the same region to
|
||||
// the set more than once.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool MouseWatcherGroup::
|
||||
void MouseWatcherGroup::
|
||||
add_region(MouseWatcherRegion *region) {
|
||||
//return _regions.insert(region).second;
|
||||
|
||||
PT(MouseWatcherRegion) pt = region;
|
||||
|
||||
// We will only bother to check for duplicates in the region list if
|
||||
// we are building opt 1 or 2. The overhead for doing this may be
|
||||
// too high if we have many regions.
|
||||
#ifdef _DEBUG
|
||||
// we are building a development Panda. The overhead for doing this
|
||||
// may be too high if we have many regions.
|
||||
#ifndef NDEBUG
|
||||
// See if the region is in the set/vector already
|
||||
Regions::const_iterator ri =
|
||||
find(_regions.begin(), _regions.end(), pt);
|
||||
if (ri != _regions.end()) {
|
||||
// Already in the set, return false
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
nassertv(ri == _regions.end());
|
||||
|
||||
// Also add it to the vizzes if we have them.
|
||||
if (_show_regions) {
|
||||
nassertv(_vizzes.size() == _regions.size());
|
||||
_vizzes.push_back(make_viz_region(pt));
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
// Not in the set, add it and return true
|
||||
_regions.push_back(pt);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -69,7 +82,7 @@ add_region(MouseWatcherRegion *region) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool MouseWatcherGroup::
|
||||
has_region(MouseWatcherRegion *region) const {
|
||||
// See if the region is in the set/vector
|
||||
// See if the region is in the vector.
|
||||
PT(MouseWatcherRegion) pt = region;
|
||||
Regions::const_iterator ri =
|
||||
find(_regions.begin(), _regions.end(), pt);
|
||||
|
|
@ -90,14 +103,23 @@ has_region(MouseWatcherRegion *region) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool MouseWatcherGroup::
|
||||
remove_region(MouseWatcherRegion *region) {
|
||||
//return _regions.erase(region) != 0;
|
||||
|
||||
// See if the region is in the set/vector
|
||||
// See if the region is in the vector.
|
||||
PT(MouseWatcherRegion) pt = region;
|
||||
Regions::iterator ri =
|
||||
find(_regions.begin(), _regions.end(), pt);
|
||||
if (ri != _regions.end()) {
|
||||
// Found it, now erase it
|
||||
#ifndef NDEBUG
|
||||
// Also remove it from the vizzes.
|
||||
if (_show_regions) {
|
||||
nassertr(_vizzes.size() == _regions.size(), false);
|
||||
size_t index = ri - _regions.begin();
|
||||
Vizzes::iterator vi = _vizzes.begin() + index;
|
||||
_show_regions_root.node()->remove_child(*vi);
|
||||
_vizzes.erase(vi);
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
_regions.erase(ri);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -134,4 +156,152 @@ find_region(const string &name) const {
|
|||
void MouseWatcherGroup::
|
||||
clear_regions() {
|
||||
_regions.clear();
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (_show_regions) {
|
||||
_show_regions_root.node()->remove_all_children();
|
||||
_vizzes.clear();
|
||||
}
|
||||
#endif // NDEBUG
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::get_num_regions
|
||||
// Access: Published
|
||||
// Description: Returns the number of regions in the group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int MouseWatcherGroup::
|
||||
get_num_regions() const {
|
||||
return _regions.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::get_region
|
||||
// Access: Published
|
||||
// Description: Returns the nth regions in the group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
MouseWatcherRegion *MouseWatcherGroup::
|
||||
get_region(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_regions.size(), NULL);
|
||||
return _regions[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcherGroup::
|
||||
output(ostream &out) const {
|
||||
out << "MouseWatcherGroup (" << _regions.size() << " regions)";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::write
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcherGroup::
|
||||
write(ostream &out, int indent_level) const {
|
||||
Regions::const_iterator ri;
|
||||
for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
|
||||
MouseWatcherRegion *region = (*ri);
|
||||
region->write(out, indent_level);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::show_regions
|
||||
// Access: Published
|
||||
// Description: Enables the visualization of all of the regions
|
||||
// handled by this MouseWatcherGroup. The supplied
|
||||
// NodePath should be the root of the 2-d scene graph
|
||||
// for the window.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcherGroup::
|
||||
show_regions(const NodePath &render2d) {
|
||||
_show_regions = true;
|
||||
_show_regions_root = render2d.attach_new_node("show_regions");
|
||||
_show_regions_root.set_bin("unsorted", 0);
|
||||
update_regions();
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
#ifndef NDEBUG
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::set_color
|
||||
// Access: Published
|
||||
// Description: Specifies the color used to draw the region
|
||||
// rectangles for the regions visualized by
|
||||
// show_regions().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcherGroup::
|
||||
set_color(const Colorf &color) {
|
||||
_color = color;
|
||||
update_regions();
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
#ifndef NDEBUG
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::hide_regions
|
||||
// Access: Published
|
||||
// Description: Stops the visualization created by a previous call to
|
||||
// show_regions().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcherGroup::
|
||||
hide_regions() {
|
||||
_show_regions_root.remove_node();
|
||||
_show_regions = false;
|
||||
_vizzes.clear();
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
#ifndef NDEBUG
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::update_regions
|
||||
// Access: Private
|
||||
// Description: Internally regenerates the show_regions()
|
||||
// visualization.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MouseWatcherGroup::
|
||||
update_regions() {
|
||||
_show_regions_root.node()->remove_all_children();
|
||||
_vizzes.clear();
|
||||
_vizzes.reserve(_regions.size());
|
||||
|
||||
Regions::const_iterator ri;
|
||||
for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
|
||||
_vizzes.push_back(make_viz_region(*ri));
|
||||
}
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
#ifndef NDEBUG
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MouseWatcherGroup::make_viz_region
|
||||
// Access: Private
|
||||
// Description: Creates a node to represent the indicated region, and
|
||||
// attaches it to the _show_regions_root. Does not add
|
||||
// it to _vizzes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *MouseWatcherGroup::
|
||||
make_viz_region(MouseWatcherRegion *region) {
|
||||
LineSegs ls("show_regions");
|
||||
ls.set_color(_color);
|
||||
|
||||
const LVecBase4f &f = region->get_frame();
|
||||
|
||||
ls.move_to(LVector3f::rfu(f[0], 0.0f, f[2]));
|
||||
ls.draw_to(LVector3f::rfu(f[1], 0.0f, f[2]));
|
||||
ls.draw_to(LVector3f::rfu(f[1], 0.0f, f[3]));
|
||||
ls.draw_to(LVector3f::rfu(f[0], 0.0f, f[3]));
|
||||
ls.draw_to(LVector3f::rfu(f[0], 0.0f, f[2]));
|
||||
|
||||
PT(PandaNode) node = ls.create();
|
||||
_show_regions_root.attach_new_node(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "pointerTo.h"
|
||||
#include "referenceCount.h"
|
||||
#include "pvector.h"
|
||||
#include "nodePath.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MouseWatcherGroup
|
||||
|
|
@ -33,19 +34,45 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA MouseWatcherGroup : virtual public ReferenceCount {
|
||||
public:
|
||||
MouseWatcherGroup();
|
||||
virtual ~MouseWatcherGroup();
|
||||
|
||||
PUBLISHED:
|
||||
bool add_region(MouseWatcherRegion *region);
|
||||
void add_region(MouseWatcherRegion *region);
|
||||
bool has_region(MouseWatcherRegion *region) const;
|
||||
bool remove_region(MouseWatcherRegion *region);
|
||||
MouseWatcherRegion *find_region(const string &name) const;
|
||||
void clear_regions();
|
||||
|
||||
int get_num_regions() const;
|
||||
MouseWatcherRegion *get_region(int n) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void show_regions(const NodePath &render2d);
|
||||
void set_color(const Colorf &color);
|
||||
void hide_regions();
|
||||
#endif // NDEBUG
|
||||
|
||||
protected:
|
||||
typedef pvector< PT(MouseWatcherRegion) > Regions;
|
||||
Regions _regions;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
void update_regions();
|
||||
PandaNode *make_viz_region(MouseWatcherRegion *region);
|
||||
|
||||
typedef pvector< PT(PandaNode) > Vizzes;
|
||||
Vizzes _vizzes;
|
||||
|
||||
bool _show_regions;
|
||||
NodePath _show_regions_root;
|
||||
Colorf _color;
|
||||
#endif // NDEBUG
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
ReferenceCount::init_type();
|
||||
|
|
|
|||
Loading…
Reference in New Issue