home *** CD-ROM | disk | FTP | other *** search
- //----------------------------------------------------------------------------
- // 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
-