openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

Window.cpp (6932B)


      1 #include <blt/syscall.h>
      2 #include <blt/os.h>
      3 #include <stdio.h>
      4 #include <win/Event.h>
      5 #include "assert.h"
      6 #include "Window.h"
      7 
      8 Window::Window(int id, int eventPort, Renderer *renderer)
      9 	:	fID(id),
     10 		fNextSibling(0),
     11 		fPreviousSibling(0),
     12 		fChildList(0),
     13 		fParent(0),
     14 		fIsVisible(false),
     15 		fEventPort(eventPort),
     16 		fPaintMsgSent(false),
     17 		fColor(0)
     18 {
     19 	if (renderer) {
     20 		// I am being attached directly to a renderer.  My clip
     21 		// region is the bounds of the renderer.
     22 		fGC.SetRenderer(renderer);
     23 		fFrame = renderer->Bounds();
     24 		fVisibleRegion.Clear();
     25 		fVisibleRegion.Include(fFrame);
     26 		fClipRegion = fVisibleRegion;
     27 		fGC.SetClipRegion(fClipRegion);
     28 	}
     29 }
     30 
     31 Window::~Window()
     32 {
     33 	if (fParent)
     34 		fParent->RemoveChild(this);
     35 }
     36 
     37 Window* Window::ChildAtPoint(int x, int y)
     38 {
     39 	// See what child is covering me at this point
     40 	for (Window *child = fChildList; child; child = child->fNextSibling) {
     41 		if (child->Frame().Contains(x, y))
     42 			return child->ChildAtPoint(x - child->Frame().left, y - child->Frame().top);
     43 	}
     44 	
     45 	return this;	// I guess that's me!
     46 }
     47 
     48 void Window::UpdateClipRegion()
     49 {
     50 	Region newClipRegion = fVisibleRegion;
     51 	Rect myScreenFrame = LocalToScreen(Bounds());
     52 
     53 	// Walk the child list.  It is ordered from front to back.
     54 	for (Window *child = fChildList; child; child = child->fNextSibling) {
     55 		// Ship hidden children (and effectively all their descendents).
     56 		if (!child->IsVisible()) {
     57 			Region empty;
     58 			child->SetVisibleRegion(empty);
     59 			continue;
     60 		}
     61 			
     62 		// My children are obscured both by my siblings and theirs.
     63 		// Create a new region.  Note that fClipRegion is initialized as
     64 		// my visible region (that is, parts of me that aren't clipped by
     65 		// my siblings). With iteration, each child window is excluded
     66 		// from it, so this clips my children against each other.
     67 		Region childClipRegion = newClipRegion;
     68 		Rect childScreenFrame = LocalToScreen(child->Frame());
     69 		childClipRegion.ConstrainTo(childScreenFrame);
     70 		child->SetVisibleRegion(childClipRegion);
     71 
     72 		// I am obscured by my child windows, remove them from my clip
     73 		// region.
     74 		newClipRegion.Exclude(childScreenFrame);
     75 	}
     76 
     77 	// Handle exposures.
     78 	//	1. Invert the old clipping region to find
     79 	//     which parts of the window were previously hidden.
     80 	//	2. Intersect that with the new clipping region to find areas
     81 	//     that have become visible.
     82 	Region exposedRegion = fClipRegion;
     83 	exposedRegion.Invert();
     84 	exposedRegion.Intersect(newClipRegion);
     85 
     86 	if (exposedRegion.Valid())
     87 		Invalidate(exposedRegion);
     88 
     89 	// Now set the new clip region for this window.
     90 	fClipRegion = newClipRegion;
     91 	fGC.SetClipRegion(fClipRegion);
     92 	fGC.SetOrigin(myScreenFrame.left, myScreenFrame.top);
     93 }
     94 
     95 void Window::AddChild(const Rect &frame, Window *child)
     96 {
     97 	child->fFrame = frame;
     98 	child->fGC.SetRenderer(fGC.GetRenderer());
     99 
    100 	child->fNextSibling = fChildList;
    101 	child->fPreviousSibling = &fChildList;
    102 	if (fChildList)
    103 		fChildList->fPreviousSibling = &child->fNextSibling;
    104 		
    105 	fChildList = child;
    106 	child->fParent = this;
    107 	if (child->IsVisible())
    108 		UpdateClipRegion();
    109 }
    110 
    111 void Window::RemoveChild(Window *window)
    112 {
    113 	ASSERT(window->parent == this);
    114 	ASSERT(window->fPreviousSibling);
    115 	
    116 	*window->fPreviousSibling = window->fNextSibling;
    117 	fParent = 0;
    118 
    119 	// Should remove all of its children
    120 
    121 	UpdateClipRegion();
    122 }
    123 
    124 void Window::MoveToFront()
    125 {
    126 	fParent->RemoveChild(this);
    127 	fParent->AddChild(fFrame, this);
    128 	UpdateClipRegion();
    129 }
    130 
    131 void Window::SetVisibleRegion(const Region &region)
    132 {
    133 	fVisibleRegion = region;
    134 	UpdateClipRegion();
    135 
    136 	if (fInRedraw) {
    137 		Region drawRegion = fCurrentRedrawRegion;
    138 		drawRegion.Intersect(fClipRegion);
    139 		fGC.SetClipRegion(drawRegion);
    140 	} else
    141 		fGC.SetClipRegion(fClipRegion);
    142 }
    143 
    144 const Region& Window::ClipRegion() const
    145 {
    146 	return fClipRegion;
    147 }
    148 
    149 void Window::MoveTo(long x, long y)
    150 {
    151 	fFrame.OffsetTo(x, y);
    152 	UpdateClipRegion();
    153 }
    154 
    155 void Window::ResizeTo(long width, long height)
    156 {
    157 	fFrame.right = fFrame.left + width;
    158 	fFrame.bottom = fFrame.top + height;
    159 	UpdateClipRegion();
    160 }
    161 
    162 void Window::Invalidate(const Region &region)
    163 {
    164 	// Erase background
    165 	for (int rect = 0; rect < region.CountRects(); rect++) {
    166 		const Rect &clipRect = region.RectAt(rect);
    167 		fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right,
    168 			clipRect.bottom, Color());
    169 	}			
    170 
    171 	fInvalidRegion.Include(region);
    172 	if (!fPaintMsgSent) {
    173 		Event paintEvent;
    174 		paintEvent.what = EVT_PAINT;
    175 		PostEvent(&paintEvent);
    176 		fPaintMsgSent = true;
    177 	}
    178 }
    179 
    180 void Window::Invalidate(const Rect &rect)
    181 {
    182 	Rect screenRect(LocalToScreen(rect));
    183 	
    184 	// Erase background
    185 	Region eraseRegion(fVisibleRegion);
    186 	Region invalRegion;
    187 	invalRegion.Include(screenRect);
    188 	eraseRegion.Intersect(invalRegion);
    189 	for (int index = 0; index < eraseRegion.CountRects(); index++) {
    190 		const Rect &clipRect = eraseRegion.RectAt(index);
    191 		fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right,
    192 			clipRect.bottom, Color());
    193 	}			
    194 
    195 	// The rect is assumed to be in window coordinates
    196 	fInvalidRegion.Include(screenRect);
    197 	if (!fPaintMsgSent) {
    198 		Event paintEvent;
    199 		paintEvent.what = EVT_PAINT;
    200 		PostEvent(&paintEvent);
    201 		fPaintMsgSent = true;
    202 	}
    203 }
    204 
    205 GraphicsContext& Window::GC()
    206 {
    207 	return fGC;
    208 }
    209 
    210 void Window::BeginPaint(Rect &out_invalidRect)
    211 {
    212 	fPaintMsgSent = false;
    213 	fInRedraw = true;
    214 	fCurrentRedrawRegion = fInvalidRegion;
    215 	fInvalidRegion.Clear();
    216 
    217 	Region drawRegion = fCurrentRedrawRegion;
    218 	drawRegion.Intersect(fClipRegion);
    219 	out_invalidRect = ScreenToLocal(drawRegion.Bounds());
    220 	fGC.SetClipRegion(drawRegion);
    221 }
    222 
    223 void Window::EndPaint()
    224 {
    225 	fInRedraw = false;
    226 }
    227 
    228 bool Window::IsVisible() const
    229 {
    230 	return fIsVisible;
    231 }
    232 
    233 char Window::Color() const
    234 {
    235 	return fColor;
    236 }
    237 
    238 void Window::SetColor(char c)
    239 {
    240 	fColor = c;
    241 }
    242 
    243 void Window::Show()
    244 {
    245 	if (!fIsVisible) {
    246 		fIsVisible = true;
    247 		if (fParent)
    248 			fParent->UpdateClipRegion();
    249 	}
    250 }
    251 
    252 void Window::Hide()
    253 {
    254 	if (fIsVisible) {
    255 		fIsVisible = false;
    256 		if (fParent)
    257 			fParent->UpdateClipRegion();
    258 	}
    259 }
    260 
    261 void Window::PostEvent(Event *event)
    262 {
    263 	event->target = fID;
    264 
    265 	msg_hdr_t header;
    266 	header.src = fEventPort;	// May break someday
    267 	header.dst = fEventPort;
    268 	header.data = event;
    269 	header.size = sizeof(Event);
    270 	old_port_send(&header);
    271 }
    272 
    273 Rect Window::LocalToScreen(const Rect &inRect) const
    274 {
    275 	Rect outRect = inRect;
    276 	for (const Window *window = this; window; window = window->fParent)
    277 		outRect.OffsetBy(window->fFrame.left, window->fFrame.top);
    278 	
    279 	return outRect;
    280 }
    281 
    282 Rect Window::ScreenToLocal(const Rect &inRect) const
    283 {
    284 	Rect outRect = inRect;
    285 	for (const Window *window = this; window; window = window->fParent)
    286 		outRect.OffsetBy(-window->fFrame.left, -window->fFrame.top);
    287 	
    288 	return outRect;
    289 }
    290 
    291 void Window::DumpChildList(int level)
    292 {
    293 	for (int i = 0; i < level; i++)
    294 		printf(" | ");
    295 		
    296 	Rect frame = Frame();
    297 	printf(" + %d %d %d %d\n", frame.left, frame.top, frame.right, frame.bottom);
    298 	for (Window *child = fChildList; child; child = child->fNextSibling) 
    299 		child->DumpChildList(level + 1);
    300 }
    301 
    302 
    303