home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C Programming Starter Kit 2.0
/
SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso
/
bc45
/
owlsrc.pak
/
DECFRAME.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-07-23
|
19KB
|
622 lines
//----------------------------------------------------------------------------
// ObjectWindows
// (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
//
// Implementation of class TDecoratedFrame
//----------------------------------------------------------------------------
#pragma hdrignore SECTION
#include <owl/owlpch.h>
#include <owl/decframe.h>
#include <owl/messageb.h>
DIAG_DECLARE_GROUP(OwlWin); // diagnostic group for windows
#if !defined(SECTION) || SECTION == 1
DEFINE_RESPONSE_TABLE2(TDecoratedFrame, TFrameWindow, TLayoutWindow)
EV_WM_ENTERIDLE,
EV_WM_MENUSELECT,
EV_WM_SIZE, // inline in decframe.h
END_RESPONSE_TABLE;
const uint BLANK_HELP = UINT_MAX;
TDecoratedFrame::TDecoratedFrame(TWindow* parent,
const char far* title,
TWindow* clientWnd,
bool trackMenuSelection,
TModule* module)
:
TLayoutWindow(parent, title, module)
{
//
// Initialize virtual bases, in case the derived-most used default ctor
//
TWindow::Init(parent, title, module);
TFrameWindow::Init(clientWnd, false);
TLayoutMetrics metrics;
TrackMenuSelection = trackMenuSelection;
MenuItemId = 0;
SettingClient = false;
if (!ClientWnd)
ClientWnd = new TWindow(this, "\007"); // create dummy placeholder
if (ClientWnd->Attr.Style & WS_BORDER) {
metrics.X.SameAs(lmParent, lmLeft);
metrics.Y.SameAs(lmParent, lmTop);
metrics.Width.SameAs(lmParent, lmRight);
metrics.Height.SameAs(lmParent, lmBottom);
}
else {
metrics.X.Set(lmLeft, lmRightOf, lmParent, lmLeft);
metrics.Y.Set(lmTop, lmBelow, lmParent, lmTop);
metrics.Width.Set(lmRight, lmLeftOf, lmParent, lmRight);
metrics.Height.Set(lmBottom, lmAbove, lmParent, lmBottom);
}
SetChildLayoutMetrics(*ClientWnd, metrics);
}
void
TDecoratedFrame::SetupWindow()
{
TRect clientRect = GetClientRect();
TFrameWindow::SetupWindow();
//
// size/position child windows. don't wait until we get the WM_SIZE event
// because by then the windows will have been displayed on the screen
//
ClientSize.cx = clientRect.right;
ClientSize.cy = clientRect.bottom;
Layout();
}
//
// Handle SetClientWindow() here to manage fixing up the layout metrics of
// all the children before & after the client is changed.
//
TWindow*
TDecoratedFrame::SetClientWindow(TWindow* clientWnd)
{
TLayoutMetrics metrics;
GetChildLayoutMetrics(*ClientWnd, metrics);
if (!clientWnd)
clientWnd = new TWindow(this, "\007"); // create dummy placeholder
clientWnd->SetParent(this);
SetChildLayoutMetrics(*clientWnd, metrics);
TWindow* oldWnd = GetClientWindow();
// Make sure that all child metrics that were based on the old client window
// get updated to the new client
//
TWindow* first = GetFirstChild();
if (first) {
TWindow* child = first;
do {
if (GetChildLayoutMetrics(*child, metrics)) {
if (metrics.X.RelWin == oldWnd)
metrics.X.RelWin = clientWnd;
if (metrics.Y.RelWin == oldWnd)
metrics.Y.RelWin = clientWnd;
if (metrics.Width.RelWin == oldWnd)
metrics.Width.RelWin = clientWnd;
if (metrics.Height.RelWin == oldWnd)
metrics.Height.RelWin = clientWnd;
SetChildLayoutMetrics(*child, metrics);
}
child = child->Next();
} while (child != first);
}
// Now let the TFrameWindow set the client. Then delete the old client if it
// was our temporary place holder. Set a flag while the client is being set
// so that RemoveChild() below knows that we are taking care of things.
//
SettingClient = true;
oldWnd = TFrameWindow::SetClientWindow(clientWnd);
SettingClient = false;
if (HIWORD(oldWnd->Title) && oldWnd->Title[0] == 007) {
oldWnd->Destroy();
delete oldWnd;
oldWnd = 0;
}
// Relayout the children to get the new client sized right
//
Layout();
return oldWnd;
}
//
// Make sure that both bases get a chance to see the child removed. TWindow's
// will be called twice, but the second call will be ignored. If we are
// removing the client, and we are not in the process of setting the client,
// then call SetClientWindow to put in a placeholder.
//
void
TDecoratedFrame::RemoveChild(TWindow* child)
{
if (child == ClientWnd && !SettingClient)
SetClientWindow(0);
TFrameWindow::RemoveChild(child);
TLayoutWindow::RemoveChild(child);
}
bool
TDecoratedFrame::PreProcessMsg(MSG& msg)
{
//
// give the decorations an opportunity to do pre-processing. don't bother
// checking the client window since it is typically in the focus chain and
// will be given an opportunity to do pre-processing
//
TWindow* firstChild = GetFirstChild();
if (firstChild) {
TWindow* child = firstChild;
do {
if (child != ClientWnd && child->HWindow &&
(child->GetWindowLong(GWL_STYLE) & WS_VISIBLE) &&
child->PreProcessMsg(msg))
return true;
child = child->Next();
} while (child != firstChild);
}
return TFrameWindow::PreProcessMsg(msg);
}
//
// Handle WM_MENUSELECT to provide hint text in the status bar based on the
// menu item id. Treat popup items seperatly and ask them for their ids.
//
void
TDecoratedFrame::EvMenuSelect(uint menuItemId, uint flags, HMENU hMenu)
{
if (TrackMenuSelection) {
if (flags == 0xFFFF && hMenu == 0) { // menu closing
TMessageBar* messageBar = (TMessageBar*)ChildWithId(IDW_STATUSBAR);
CHECK(messageBar);
messageBar->SetHintText(0);
MenuItemId = 0; // restore status bar to normal look
}
else if (flags & MF_POPUP) {
TMenu popupMenu(hMenu);
int count = popupMenu.GetMenuItemCount();
for (int pos = 0;
pos < count && popupMenu.GetSubMenu(pos) != HMENU(menuItemId);
pos++)
;
MenuItemId = popupMenu.GetMenuItemID(pos);
}
else if (flags & (MF_SEPARATOR | MF_MENUBREAK | MF_MENUBARBREAK)
|| (menuItemId >= IDW_FIRSTMDICHILD && menuItemId < IDW_FIRSTMDICHILD+9)) {
MenuItemId = BLANK_HELP; // display an empty help message
// could also restore bar at this point too
}
else {
MenuItemId = menuItemId; // display a help message with this string Id
}
}
}
void
TDecoratedFrame::EvEnterIdle(uint source, HWND hWndDlg)
{
if (source == MSGF_MENU && MenuItemId) {
char buf[128];
TMessageBar* messageBar = (TMessageBar*)ChildWithId(IDW_STATUSBAR);
CHECK(messageBar);
if (MenuItemId != BLANK_HELP) {
int numBytes = GetModule()->LoadString(MenuItemId, buf, sizeof(buf));
if (numBytes == 0 && MergeModule != 0)
numBytes = MergeModule->LoadString(MenuItemId, buf, sizeof(buf));
WARNX(OwlWin, numBytes == 0, 0,
"TDecoratedFrame::EvEnterIdle LoadString("
<< *GetModule() << "," << MenuItemId << ") Failed");
}
else
*buf = 0;
messageBar->SetHintText(buf);
MenuItemId = 0; // Don't repaint on subsequent EvEnterIdle's
}
TFrameWindow::EvEnterIdle(source, hWndDlg);
}
//
// Get or set location codes stashed in the style long for a decoration
//
inline TDecoratedFrame::TLocation
GetLocation(TWindow& w) {
return TDecoratedFrame::TLocation(uint16(w.Attr.Style) & 0x0F00);
}
inline void
SetLocation(TWindow& w, TDecoratedFrame::TLocation loc) {
w.Attr.Style = (w.Attr.Style&~0x0F00) | loc;
}
//
// Find first sibling of a decoration in the same location
//
struct TSiblingSearch {
TWindow* Decoration;
TDecoratedFrame::TLocation Location;
TWindow* Sibling;
TSiblingSearch(TWindow* decoration, TDecoratedFrame::TLocation location)
{
Decoration = decoration;
Sibling = 0;
Location = location;
}
};
static bool
FindSibling(TWindow* win, void* param)
{
TSiblingSearch* search = (TSiblingSearch*)param;
if (win == search->Decoration)
return true;
else if (GetLocation(*win) == search->Location && win->IsWindowVisible())
search->Sibling = win;
return false;
}
LRESULT
TDecoratedFrame::EvCommand(uint id, HWND hWndCtl, uint notifyCode)
{
if (hWndCtl == 0) {
TWindow* decoration = ChildWithId(id);
if (decoration) {
bool visible = decoration->IsWindowVisible();
TLocation location = GetLocation(*decoration);
TSiblingSearch search(decoration, location);
FirstThat(FindSibling, &search);
if (!search.Sibling)
search.Sibling = ClientWnd;
//
// toggle the window's visibility
//
if (visible)
RemoveChildLayoutMetrics(*decoration);
else
switch (location) {
case Top:
InsertAtTop(*decoration, search.Sibling);
break;
case Bottom:
InsertAtBottom(*decoration, search.Sibling);
break;
case Left:
InsertAtLeft(*decoration, search.Sibling);
break;
case Right:
InsertAtRight(*decoration, search.Sibling);
break;
}
Layout();
decoration->ShowWindow(visible ? SW_HIDE : SW_SHOW);
return 0;
}
}
return TFrameWindow::EvCommand(id, hWndCtl, notifyCode);
}
void
TDecoratedFrame::EvCommandEnable(TCommandEnabler& commandEnabler)
{
TWindow* decoration = ChildWithId(commandEnabler.Id);
if (!decoration)
TFrameWindow::EvCommandEnable(commandEnabler);
else {
commandEnabler.Enable();
commandEnabler.SetCheck(decoration->IsWindowVisible() ?
TCommandEnabler::Checked :
TCommandEnabler::Unchecked);
}
}
void
TDecoratedFrame::InsertAtTop(TWindow& decoration, TWindow* insertAbove)
{
TLayoutMetrics metrics;
TWindow* insertBelow;
//
// get the layout metrics for "insertAbove" (the window the decoration is
// going to be inserted above)
//
GetChildLayoutMetrics(*insertAbove, metrics);
insertBelow = metrics.Y.RelWin;
//
// if "insertAbove" has a border then set its top edge to be the same as
// the decoration's bottom edge; otherwise place its top edge below the
// decoration's bottom edge
//
metrics.Y.Set(lmTop,
insertAbove->Attr.Style & WS_BORDER ? lmSameAs : lmBelow,
&decoration, lmBottom);
SetChildLayoutMetrics(*insertAbove, metrics);
//
// now set the layout metrics for the decoration so its top edge is the same
// as the bottom edge of "insertBelow"(i.e. they overlap)
//
if (!insertBelow)
metrics.Y.SameAs(lmParent, lmTop);
else
metrics.Y.Set(lmTop, lmSameAs, insertBelow, lmBottom);
metrics.Height.MyEdge = lmHeight;
metrics.Height.Relationship = lmAsIs;
metrics.X.Set(lmLeft, lmSameAs, lmParent, lmLeft);
metrics.Width.Set(lmRight, lmSameAs, lmParent, lmRight);
SetChildLayoutMetrics(decoration, metrics);
}
void
TDecoratedFrame::InsertAtBottom(TWindow& decoration, TWindow* insertBelow)
{
TLayoutMetrics metrics;
TWindow* insertAbove;
//
// get the layout metrics for "insertBelow"(the window the decoration is
// going to be inserted below)
//
GetChildLayoutMetrics(*insertBelow, metrics);
if (insertBelow == ClientWnd) {
insertAbove = metrics.Height.RelWin;
//
// if the client window has a border then set the client window's bottom
// to be the same as the top edge of the decoration; otherwise set the
// client window's bottom edge to be above the decoration's top edge
//
metrics.Height.Set(lmBottom,
ClientWnd->Attr.Style & WS_BORDER ? lmSameAs : lmAbove,
&decoration, lmTop);
}
else {
insertAbove = metrics.Y.RelWin;
//
// set the bottom edge of "insertBelow" to be the same as the top edge of
// the decoration
//
metrics.Y.Set(lmBottom, lmSameAs, &decoration, lmTop);
}
SetChildLayoutMetrics(*insertBelow, metrics);
//
// now set the layout metrics for the decoration so its bottom edge is the
// same as the top edge of "insertAbove"
//
if (!insertAbove)
metrics.Y.SameAs(lmParent, lmBottom);
else
metrics.Y.Set(lmBottom, lmSameAs, insertAbove, lmTop);
metrics.Height.MyEdge = lmHeight;
metrics.Height.Relationship = lmAsIs;
metrics.X.Set(lmLeft, lmSameAs, lmParent, lmLeft);
metrics.Width.Set(lmRight, lmSameAs, lmParent, lmRight);
SetChildLayoutMetrics(decoration, metrics);
}
void
TDecoratedFrame::InsertAtLeft(TWindow& decoration, TWindow* insertLeftOf)
{
TLayoutMetrics metrics;
TWindow* insertRightOf;
//
// get the layout metrics for "insertLeftOf"(the window the decoration is
// going to be inserted to the left of)
//
GetChildLayoutMetrics(*insertLeftOf, metrics);
insertRightOf = metrics.X.RelWin;
//
// if "insertLeftOf" has a border then set its left edge to be the same as
// the decoration's right edge; otherwise place its left edge one pixel to
// the right of the decoration's right edge
//
metrics.X.Set(lmLeft,
insertLeftOf->Attr.Style & WS_BORDER ? lmSameAs : lmRightOf,
&decoration, lmRight);
SetChildLayoutMetrics(*insertLeftOf, metrics);
//
// now set the layout metrics for the decoration so it's left edge is the
// same as the right edge of "insertRightOf"
//
if (!insertRightOf)
metrics.X.SameAs(lmParent, lmLeft);
else
metrics.X.Set(lmLeft, lmSameAs, insertRightOf, lmRight);
metrics.Width.MyEdge = lmWidth;
metrics.Width.Relationship = lmAsIs;
//
// if the client window has a border then place the decoration so its
// "y" and "bottom" are the same as the client windows; otherwise place
// its "y" above the client window's "y" and its "bottom" below the client
// window's "bottom"
//
// this way if there are top or bottom decorations they will be tiled
// over/under the left/right decorations
//
if (ClientWnd->Attr.Style & WS_BORDER) {
metrics.Y.SameAs(ClientWnd, lmTop);
metrics.Height.SameAs(ClientWnd, lmBottom);
}
else {
metrics.Y.Set(lmTop, lmAbove, ClientWnd, lmTop);
metrics.Height.Set(lmBottom, lmBelow, ClientWnd, lmBottom);
}
SetChildLayoutMetrics(decoration, metrics);
}
void
TDecoratedFrame::InsertAtRight(TWindow& decoration, TWindow* insertRightOf)
{
TLayoutMetrics metrics;
TWindow* insertLeftOf;
//
// get the layout metrics for "insertRightOf"(the window the decoration is
// going to be inserted to the right of)
//
GetChildLayoutMetrics(*insertRightOf, metrics);
if (insertRightOf == ClientWnd) {
insertLeftOf = metrics.Width.RelWin;
//
// if the client window has a border then set the client window's right
// edge to be the same as the left edge of the decoration; otherwise set
// the client window's right edge to be one pixel to the left of the
// decoration's left edge
//
metrics.Width.Set(lmRight,
ClientWnd->Attr.Style & WS_BORDER ? lmSameAs : lmLeftOf,
&decoration, lmLeft);
}
else {
insertLeftOf = metrics.X.RelWin;
//
// set the right edge of "insertRightOf" to be the same as the left edge of
// the decoration
//
metrics.X.Set(lmRight, lmSameAs, &decoration, lmLeft);
}
SetChildLayoutMetrics(*insertRightOf, metrics);
//
// now set the layout metrics for the decoration so its right edge is the
// same as the left edge of "insertLeftOf"
//
if (!insertLeftOf)
metrics.X.Set(lmRight, lmSameAs, lmParent, lmRight);
else
metrics.X.Set(lmRight, lmSameAs, insertLeftOf, lmLeft);
metrics.Width.MyEdge = lmWidth;
metrics.Width.Relationship = lmAsIs;
//
// if the client window has a border then place the decoration so its
// "y" and "bottom" are the same as the client windows; otherwise place
// its "y" above the client window's "y" and its "bottom" below the client
// window's "bottom"
//
// this way if there are top or bottom decorations they will be tiled
// over/under the left/right decorations
//
if (ClientWnd->Attr.Style & WS_BORDER) {
metrics.Y.SameAs(ClientWnd, lmTop);
metrics.Height.SameAs(ClientWnd, lmBottom);
}
else {
metrics.Y.Set(lmTop, lmAbove, ClientWnd, lmTop);
metrics.Height.Set(lmBottom, lmBelow, ClientWnd, lmBottom);
}
SetChildLayoutMetrics(decoration, metrics);
}
//
// Insert a decoration window into position at one of the four edges.
//
void
TDecoratedFrame::Insert(TWindow& decoration, TLocation location)
{
SetLocation(decoration, location); // keep loc for removal & sibling inserts
// Make sure the decoration has clipsiblings style, since our rearranging
// causes corners to overlap sometimes.
//
decoration.Attr.Style |= WS_CLIPSIBLINGS;
if (decoration.HWindow)
decoration.SetWindowLong(GWL_STYLE,
decoration.GetWindowLong(GWL_STYLE)|WS_CLIPSIBLINGS);
decoration.SetParent(this);
RemoveChildLayoutMetrics(decoration); // in case this is a re-insert
if (decoration.Attr.Style & WS_VISIBLE)
switch (location) {
case Top:
InsertAtTop(decoration, ClientWnd);
break;
case Bottom:
InsertAtBottom(decoration, ClientWnd);
break;
case Left:
InsertAtLeft(decoration, ClientWnd);
break;
case Right:
InsertAtRight(decoration, ClientWnd);
break;
}
}
#endif
#if !defined(SECTION) || SECTION == 2
IMPLEMENT_STREAMABLE3(TDecoratedFrame, TFrameWindow, TLayoutWindow, TWindow);
void*
TDecoratedFrame::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
ReadVirtualBase((TFrameWindow*)GetObject(), is);
ReadBaseObject((TLayoutWindow*)GetObject(), is);
return GetObject();
}
void
TDecoratedFrame::Streamer::Write(opstream& os) const
{
WriteVirtualBase((TFrameWindow*)GetObject(), os);
WriteBaseObject((TLayoutWindow*)GetObject(), os);
}
#endif