- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1672 lines
37 KiB
C++
1672 lines
37 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Implementation of TOleWindow. Window class that supports Ole2
|
|
// container & server using OCF TOcView & TOcRemView
|
|
//----------------------------------------------------------------------------
|
|
#define INC_OLE2
|
|
#include <owl/owlpch.h>
|
|
#include <owl/window.h>
|
|
#include <owl/gdiobjec.h>
|
|
#include <owl/uihandle.h>
|
|
#include <owl/scroller.h>
|
|
#include <ocf/ocdoc.h>
|
|
#include <ocf/ocview.h>
|
|
#include <owl/docview.rh>
|
|
#include <owl/oleview.rh>
|
|
#include <owl/oleframe.h>
|
|
#include <owl/olewindo.h>
|
|
#include <owl/oledlg.h>
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Size of rectangle in two clks must occur to be a doubleClick
|
|
//
|
|
#if !defined(BI_PLAT_WIN32)
|
|
TSize DblClkDelta(3, 3);
|
|
#else
|
|
TSize DblClkDelta(GetSystemMetrics(SM_CXDOUBLECLK)/2,
|
|
GetSystemMetrics(SM_CYDOUBLECLK)/2);
|
|
#endif
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TOleClientDC
|
|
//
|
|
|
|
TOleClientDC::TOleClientDC(TOleWindow& win, bool scale)
|
|
:
|
|
TClientDC(win)
|
|
{
|
|
win.SetupDC(*this, scale);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TOleWindow
|
|
//
|
|
|
|
DEFINE_RESPONSE_TABLE1(TOleWindow, TWindow)
|
|
EV_WM_PAINT,
|
|
EV_WM_LBUTTONDOWN,
|
|
EV_WM_RBUTTONDOWN,
|
|
EV_WM_LBUTTONDBLCLK,
|
|
EV_WM_MOUSEMOVE,
|
|
EV_WM_LBUTTONUP,
|
|
EV_WM_SIZE,
|
|
EV_WM_MDIACTIVATE,
|
|
EV_WM_MOUSEACTIVATE,
|
|
EV_WM_SETFOCUS,
|
|
EV_WM_SETCURSOR,
|
|
EV_WM_DROPFILES,
|
|
EV_WM_VSCROLL,
|
|
EV_WM_HSCROLL,
|
|
EV_WM_MENUSELECT,
|
|
|
|
EV_COMMAND_ENABLE(CM_FILECLOSE, CeFileClose),
|
|
|
|
EV_COMMAND(CM_EDITDELETE, CmEditDelete),
|
|
EV_COMMAND_ENABLE(CM_EDITDELETE, CeEditDelete),
|
|
EV_COMMAND(CM_EDITCUT, CmEditCut),
|
|
EV_COMMAND_ENABLE(CM_EDITCUT, CeEditCut),
|
|
EV_COMMAND(CM_EDITCOPY, CmEditCopy),
|
|
EV_COMMAND_ENABLE(CM_EDITCOPY, CeEditCopy),
|
|
EV_COMMAND(CM_EDITPASTE, CmEditPaste),
|
|
EV_COMMAND_ENABLE(CM_EDITPASTE, CeEditPaste),
|
|
EV_COMMAND(CM_EDITPASTESPECIAL, CmEditPasteSpecial),
|
|
EV_COMMAND_ENABLE(CM_EDITPASTESPECIAL, CeEditPasteSpecial),
|
|
EV_COMMAND(CM_EDITPASTELINK, CmEditPasteLink),
|
|
EV_COMMAND_ENABLE(CM_EDITPASTELINK, CeEditPasteLink),
|
|
EV_COMMAND(CM_EDITINSERTOBJECT, CmEditInsertObject),
|
|
EV_COMMAND_ENABLE(CM_EDITINSERTOBJECT, CeEditInsertObject),
|
|
EV_COMMAND_ENABLE(CM_EDITLINKS, CeEditLinks),
|
|
EV_COMMAND(CM_EDITLINKS, CmEditLinks),
|
|
EV_COMMAND_ENABLE(CM_EDITOBJECT, CeEditObject),
|
|
EV_COMMAND_ENABLE(CM_EDITCONVERT, CeEditConvert),
|
|
EV_COMMAND(CM_EDITCONVERT, CmEditConvert),
|
|
EV_COMMAND_ENABLE(CM_EDITSHOWOBJECTS, CeEditShowObjects),
|
|
EV_COMMAND(CM_EDITSHOWOBJECTS, CmEditShowObjects),
|
|
|
|
EV_MESSAGE(WM_OCEVENT, EvOcEvent),
|
|
// EV_OC_VIEWDISCARDUNDO, //!CQ not processing this yet...
|
|
|
|
// Container specific messages
|
|
//
|
|
EV_OC_VIEWPARTINVALID,
|
|
EV_OC_VIEWTITLE,
|
|
EV_OC_VIEWSETTITLE,
|
|
EV_OC_VIEWBORDERSPACEREQ,
|
|
EV_OC_VIEWBORDERSPACESET,
|
|
EV_OC_VIEWDROP,
|
|
EV_OC_VIEWDRAG,
|
|
EV_OC_VIEWSCROLL,
|
|
EV_OC_VIEWGETSCALE,
|
|
EV_OC_VIEWGETSITERECT,
|
|
EV_OC_VIEWSETSITERECT,
|
|
EV_OC_VIEWPARTACTIVATE,
|
|
EV_OC_VIEWPASTEOBJECT,
|
|
|
|
// Server specific messages
|
|
//
|
|
EV_OC_VIEWPAINT,
|
|
EV_OC_VIEWSAVEPART,
|
|
EV_OC_VIEWLOADPART,
|
|
EV_OC_VIEWINSMENUS,
|
|
EV_OC_VIEWSHOWTOOLS,
|
|
EV_OC_VIEWGETPALETTE,
|
|
EV_OC_VIEWCLIPDATA,
|
|
EV_OC_VIEWSETDATA,
|
|
EV_OC_VIEWCLOSE,
|
|
EV_OC_VIEWPARTSIZE,
|
|
EV_OC_VIEWOPENDOC,
|
|
EV_OC_VIEWATTACHWINDOW,
|
|
EV_OC_VIEWSETSCALE,
|
|
EV_OC_VIEWGETITEMNAME,
|
|
EV_OC_VIEWSETLINK,
|
|
EV_OC_VIEWBREAKLINK,
|
|
EV_OC_VIEWDOVERB,
|
|
END_RESPONSE_TABLE;
|
|
|
|
TOleWindow::TOleWindow(TWindow* parent, TModule* module)
|
|
:
|
|
TWindow(parent, 0, module),
|
|
Pos(0, 0, 0, 0),
|
|
Remote(false),
|
|
ShowObjects(false)
|
|
{
|
|
// Derived class will need to create a OcDocument object to hold the ole
|
|
// parts that we create and a OcView to provide ole services
|
|
//
|
|
OcApp = 0;
|
|
OcDoc = 0;
|
|
OcView = 0;
|
|
|
|
Init();
|
|
}
|
|
|
|
void
|
|
TOleWindow::Init()
|
|
{
|
|
// Clip children to not paint on in-place servers, & clip siblings to not
|
|
// paint on floating tool palettes
|
|
//
|
|
Attr.Style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
|
|
|
Attr.AccelTable = IDA_OLEVIEW;
|
|
DragHit = TUIHandle::Outside;
|
|
DragPart = 0;
|
|
DragDC = 0;
|
|
|
|
// Minimum part size
|
|
//
|
|
HDC dc = GetDC(0);
|
|
MinWidth = GetDeviceCaps(dc, LOGPIXELSX) / 4;
|
|
MinHeight = GetDeviceCaps(dc, LOGPIXELSY) / 4;
|
|
ReleaseDC(0, dc);
|
|
|
|
|
|
// Snag the OcApp from the TOleFrame object for quick reference
|
|
//
|
|
TOleFrame* olefr = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(), TOleFrame);
|
|
CHECK(olefr);
|
|
OcApp = olefr->GetOcApp();
|
|
OcApp->AddRef();
|
|
}
|
|
|
|
TOleWindow::~TOleWindow()
|
|
{
|
|
// Let the OC objects go. They will delete themselves when they can
|
|
// If it's a remote view, then the last release is called by the container.
|
|
//
|
|
if (OcDoc)
|
|
OcDoc->Close(); // close all the embedded parts first
|
|
if (OcView && !IsRemote()) {
|
|
OcView->ReleaseObject(); // use ReleaseObject here to tell it we are gone
|
|
OcView = 0;
|
|
}
|
|
|
|
delete OcDoc;
|
|
if (OcApp) {
|
|
OcApp->Release();
|
|
OcApp = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Perform normal SetupWindow, plus let the OcView object know our HWND so that
|
|
// it can talk to us.
|
|
//
|
|
void
|
|
TOleWindow::SetupWindow()
|
|
{
|
|
if (!OcView)
|
|
CreateOcView(0, false, 0); // don't have much context by this time
|
|
CHECK(OcView);
|
|
TWindow::SetupWindow();
|
|
OcView->SetupWindow(*this, IsRemote());
|
|
}
|
|
|
|
//
|
|
// Called to perform the actual setting up of the OcView member
|
|
// Derived class needs to construct the TOcView/TOcRemView here & return it
|
|
//
|
|
TOcView*
|
|
TOleWindow::CreateOcView(TRegLink* link, bool isRemote, IUnknown* outer)
|
|
{
|
|
if (!OcDoc)
|
|
OcDoc = new TOcDocument(*GetOcApp());
|
|
|
|
if (!OcView) {
|
|
TRegList* regList = link ? &link->GetRegList() : 0;
|
|
|
|
// Create a remote view on the server document if it embeded, else make a
|
|
// normal, container view
|
|
//
|
|
if (isRemote)
|
|
OcView = new TOcRemView(*GetOcDoc(), regList, outer);
|
|
else
|
|
OcView = new TOcView(*GetOcDoc(), regList, outer);
|
|
|
|
Remote = isRemote;
|
|
}
|
|
return OcView;
|
|
}
|
|
|
|
//
|
|
// Handle the command enabling for a range of command IDs for verbs
|
|
//
|
|
void
|
|
TOleWindow::EvCommandEnable(TCommandEnabler& commandEnabler)
|
|
{
|
|
if (CM_EDITFIRSTVERB <= commandEnabler.Id && commandEnabler.Id <= CM_EDITLASTVERB) {
|
|
CeEditVerbs(commandEnabler);
|
|
}
|
|
else if (IsRemote()) {
|
|
// Get the focus, in case it is a child that should receive the cmds
|
|
// fall back to this window in case the Ole menu bar stole focus!
|
|
//
|
|
HWND hCmdTarget = ::GetFocus();
|
|
if (hCmdTarget != HWindow && !IsChild(hCmdTarget))
|
|
hCmdTarget = HWindow;
|
|
|
|
RouteCommandEnable(hCmdTarget, commandEnabler);
|
|
}
|
|
else {
|
|
TWindow::EvCommandEnable(commandEnabler);
|
|
}
|
|
}
|
|
|
|
//
|
|
// processing a range of command IDs for verbs
|
|
//
|
|
LRESULT
|
|
TOleWindow::EvCommand(uint id, HWND hWndCtl, uint notifyCode)
|
|
{
|
|
if (hWndCtl == 0) {
|
|
if (CM_EDITFIRSTVERB <= id && id <= CM_EDITLASTVERB) {
|
|
EvDoVerb(id - CM_EDITFIRSTVERB);
|
|
return 0;
|
|
}
|
|
}
|
|
return TWindow::EvCommand(id, hWndCtl, notifyCode);
|
|
}
|
|
|
|
//
|
|
// Intercept CanClose() to interpose OpenEdit semantics. Ole 2 servers don't
|
|
// prompt the user on close--just save & close.
|
|
//
|
|
bool
|
|
TOleWindow::CanClose()
|
|
{
|
|
// We don't want to close the view for DLL servers
|
|
//
|
|
if (IsOpenEditing() && !OcApp->IsOptionSet(amExeMode)) {
|
|
TOleFrame* olefr = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(), TOleFrame);
|
|
CHECK(olefr);
|
|
olefr->ShowWindow(SW_HIDE);
|
|
OleShutDown();
|
|
return false;
|
|
}
|
|
|
|
if (GetOcRemView() || TWindow::CanClose()) {
|
|
if (OcDoc)
|
|
OcDoc->Close();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Notify part
|
|
//
|
|
void
|
|
TOleWindow::InvalidatePart(TOcInvalidate invalid)
|
|
{
|
|
if (GetOcRemView())
|
|
GetOcRemView()->Invalidate(invalid);
|
|
}
|
|
|
|
//
|
|
// Is the window in Open-Edit mode
|
|
//
|
|
bool
|
|
TOleWindow::IsOpenEditing() const
|
|
{
|
|
TOcRemView* ocRemView = const_cast<TOleWindow*>(this)->GetOcRemView();
|
|
return ocRemView && ocRemView->GetState() == TOcRemView::OpenEditing;
|
|
}
|
|
|
|
//
|
|
// Handles the file File>Close menu option for server app
|
|
//
|
|
void
|
|
TOleWindow::CeFileClose(TCommandEnabler& ce)
|
|
{
|
|
// if open editing server, reflect the container's name in "close" option
|
|
//
|
|
if (IsOpenEditing()) {
|
|
string optName = GetModule()->LoadString(IDS_CLOSESERVER);
|
|
TString title = GetOcRemView()->GetContainerTitle();
|
|
if (title.Length() > 0)
|
|
optName += title;
|
|
ce.SetText(optName.c_str());
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TOleWindow::CeEditInsertObject(TCommandEnabler& ce)
|
|
{
|
|
ce.Enable(OcApp && OcView);
|
|
}
|
|
|
|
//
|
|
// Get the insertion point for the embedded object in device units.
|
|
// Currently we're using only the top left point for position, size is
|
|
// redundant.
|
|
//
|
|
void
|
|
TOleWindow::GetInsertPosition(TRect& rect)
|
|
{
|
|
TOleClientDC dc(*this);
|
|
|
|
// Default insertion point is at 0.5" away from current viewport origin
|
|
//
|
|
rect.left = dc.GetDeviceCaps(LOGPIXELSX) / 2; // in pixels
|
|
rect.top = dc.GetDeviceCaps(LOGPIXELSY) / 2; // in pixels
|
|
|
|
// Adjust the position of embedded object to be in pixels and reflect the
|
|
// zoom factor.
|
|
//
|
|
dc.LPtoDP((TPoint*)&rect, 1);
|
|
|
|
// No size yet.
|
|
//
|
|
rect.right = rect.left;
|
|
rect.bottom = rect.top;
|
|
}
|
|
|
|
//
|
|
// Insert an OLE object into the view
|
|
//
|
|
void
|
|
TOleWindow::CmEditInsertObject()
|
|
{
|
|
PRECONDITION(OcView);
|
|
TOcInitInfo initInfo(OcView);
|
|
|
|
if (OcApp->Browse(initInfo)) {
|
|
TRect rect;
|
|
GetInsertPosition(rect);
|
|
SetSelection(new TOcPart(*GetOcDoc(), initInfo, rect));
|
|
|
|
OcView->Rename();
|
|
InvalidatePart(invView);
|
|
}
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditDelete(TCommandEnabler& ce)
|
|
{
|
|
ce.Enable(DragPart != 0);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditDelete()
|
|
{
|
|
if (!DragPart)
|
|
return;
|
|
|
|
TOcPartChangeInfo changeInfo(DragPart, invData|invView);
|
|
EvOcViewPartInvalid(changeInfo);
|
|
|
|
DragPart->Delete();
|
|
DragPart = 0;
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditCut(TCommandEnabler& ce)
|
|
{
|
|
ce.Enable(DragPart != 0);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditCut()
|
|
{
|
|
DragPart->Detach();
|
|
OcApp->Copy(DragPart);
|
|
SetSelection(0);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditCopy(TCommandEnabler& ce)
|
|
{
|
|
ce.Enable(DragPart != 0);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditCopy()
|
|
{
|
|
if (DragPart)
|
|
OcApp->Copy(DragPart);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditPasteLink(TCommandEnabler& ce)
|
|
{
|
|
PRECONDITION(OcApp && OcView);
|
|
ce.Enable(OcApp->EnableEditMenu(meEnablePasteLink, OcView));
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditPasteLink()
|
|
{
|
|
OcView->Paste(true);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditPaste(TCommandEnabler& ce)
|
|
{
|
|
PRECONDITION(OcApp && OcView);
|
|
ce.Enable(OcApp->EnableEditMenu(meEnablePaste, OcView));
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditPaste()
|
|
{
|
|
OcView->Paste(false);
|
|
InvalidatePart(invView);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditPasteSpecial(TCommandEnabler& ce)
|
|
{
|
|
PRECONDITION(OcApp && OcView);
|
|
ce.Enable(OcApp->EnableEditMenu(meEnableBrowseClipboard, OcView));
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditPasteSpecial()
|
|
{
|
|
TOcInitInfo initInfo(GetOcView());
|
|
|
|
if (GetOcView()->BrowseClipboard(initInfo)) {
|
|
if (!OcView->PasteNative(initInfo)) { // Not native data
|
|
EvOcViewPasteObject(initInfo);
|
|
}
|
|
InvalidatePart(invView);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Append the object menu and enable it
|
|
//
|
|
void
|
|
TOleWindow::CeEditObject(TCommandEnabler& ce)
|
|
{
|
|
// Downcast to get at submenu item
|
|
//
|
|
TMenuItemEnabler* me = TYPESAFE_DOWNCAST(&ce, TMenuItemEnabler);
|
|
if (!me)
|
|
return;
|
|
|
|
int verbPos = me->GetPosition(); // remember the verb menu position
|
|
TMenu editMenu(me->GetMenu());
|
|
|
|
string optName = GetModule()->LoadString(IDS_EDITOBJECT);
|
|
if (!DragPart) {
|
|
// Remove the verb menu, if any
|
|
//
|
|
if (editMenu.GetSubMenu(verbPos)) {
|
|
editMenu.DeleteMenu(verbPos, MF_BYPOSITION);
|
|
editMenu.InsertMenu(verbPos, MF_GRAYED | MF_BYPOSITION | MF_STRING,
|
|
CM_EDITOBJECT, optName.c_str());
|
|
}
|
|
ce.Enable(false);
|
|
return;
|
|
}
|
|
|
|
// Add verb menu
|
|
//
|
|
TOcVerb ocVerb;
|
|
TMenu* verbMenu = CreateVerbPopup(ocVerb);
|
|
string newMenuName(OleStr(ocVerb.TypeName));
|
|
newMenuName += ' ';
|
|
newMenuName += optName;
|
|
editMenu.ModifyMenu(verbPos, MF_ENABLED | MF_BYPOSITION | MF_POPUP,
|
|
(uint)verbMenu->GetHandle(), newMenuName.c_str());
|
|
delete verbMenu;
|
|
ce.Enable(true);
|
|
}
|
|
|
|
//
|
|
// Command enabler for "Edit" "Convert..." option
|
|
//
|
|
void
|
|
TOleWindow::CeEditConvert(TCommandEnabler& ce)
|
|
{
|
|
ce.Enable(DragPart != 0);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditConvert()
|
|
{
|
|
OcApp->Convert(DragPart, false);
|
|
}
|
|
|
|
//
|
|
// Command enabler for "Edit" "Links..." option
|
|
//
|
|
void
|
|
TOleWindow::CeEditLinks(TCommandEnabler& ce)
|
|
{
|
|
PRECONDITION(OcApp && OcView);
|
|
ce.Enable(OcApp->EnableEditMenu(meEnableBrowseLinks, OcView));
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditLinks()
|
|
{
|
|
PRECONDITION(OcView);
|
|
OcView->BrowseLinks();
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditVerbs(TCommandEnabler& ce)
|
|
{
|
|
ce.Enable(DragPart != 0);
|
|
}
|
|
|
|
void
|
|
TOleWindow::CmEditShowObjects()
|
|
{
|
|
ShowObjects = !ShowObjects;
|
|
Invalidate();
|
|
}
|
|
|
|
void
|
|
TOleWindow::CeEditShowObjects(TCommandEnabler& ce)
|
|
{
|
|
ce.SetCheck(ShowObjects ? TCommandEnabler::Checked : TCommandEnabler::Unchecked);
|
|
}
|
|
|
|
//
|
|
// Has in-place active part?
|
|
//
|
|
bool
|
|
TOleWindow::HasActivePart()
|
|
{
|
|
return OcView->GetActivePart() != 0;
|
|
}
|
|
|
|
//
|
|
// Change cursor shape if within an embedded object
|
|
//
|
|
bool
|
|
TOleWindow::EvSetCursor(HWND wnd, uint hitTest, uint mouseMsg)
|
|
{
|
|
TPoint pt;
|
|
GetCursorPos(pt);
|
|
ScreenToClient(pt);
|
|
TOcPart* p = OcView->GetActivePart();
|
|
|
|
if (hitTest == HTCLIENT) {
|
|
if (p) { // there is an activated part
|
|
TUIHandle handle(p->GetRect(), TUIHandle::Framed);
|
|
if (handle.HitTest(pt) == TUIHandle::MidCenter) {
|
|
return false; // let the inplace server set its cursor shape
|
|
}
|
|
else { // use arrow cursor
|
|
::SetCursor(::LoadCursor(0, IDC_ARROW));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set cursor for resize when cursor over inactive part
|
|
//
|
|
if (!p && DragPart) {
|
|
TRect rect(DragPart->GetRect());
|
|
TOleClientDC dc(*this);
|
|
dc.LPtoDP((TPoint*)&rect, 2);
|
|
|
|
TUIHandle handle(rect, TUIHandle::HandlesIn | TUIHandle::Grapples |
|
|
TUIHandle::Framed);
|
|
|
|
if (handle.HitTest(pt) != TUIHandle::Outside)
|
|
::SetCursor(::LoadCursor(0, TResId(handle.GetCursorId(handle.HitTest(pt)))));
|
|
else
|
|
::SetCursor(::LoadCursor(0, IDC_ARROW));
|
|
|
|
return true;
|
|
}
|
|
|
|
return ShowCursor(wnd, hitTest, mouseMsg);
|
|
}
|
|
|
|
//
|
|
// Show cursor when it's not in an embedded object
|
|
//
|
|
bool
|
|
TOleWindow::ShowCursor(HWND /*wnd*/, uint /*hitTest*/, uint /*mouseMsg*/)
|
|
{
|
|
::SetCursor(::LoadCursor(0, IDC_ARROW));
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Accept dropped file from file manager
|
|
//
|
|
void
|
|
TOleWindow::EvDropFiles(TDropInfo dropInfo)
|
|
{
|
|
int fileCount = dropInfo.DragQueryFileCount();
|
|
for (int index = 0; index < fileCount; index++) {
|
|
int fileLength = dropInfo.DragQueryFileNameLen(index)+1;
|
|
OLECHAR* filePath = new OLECHAR[fileLength];
|
|
dropInfo.DragQueryFile(index, OleStr(filePath), fileLength);
|
|
|
|
TOcInitInfo initInfo(ihEmbed, iwFile, OcView);
|
|
initInfo.Path = filePath;
|
|
|
|
TRect rect;
|
|
GetInsertPosition(rect);
|
|
SetSelection(new TOcPart(*GetOcDoc(), initInfo, rect));
|
|
|
|
OcView->Rename();
|
|
InvalidatePart(invView);
|
|
|
|
delete [] filePath;
|
|
}
|
|
dropInfo.DragFinish();
|
|
}
|
|
|
|
//
|
|
// Handle left double-click message
|
|
//
|
|
void
|
|
TOleWindow::EvLButtonDblClk(uint modKeys, TPoint& point)
|
|
{
|
|
PRECONDITION(GetOcDoc() && GetOcView());
|
|
TOleClientDC dc(*this);
|
|
dc.DPtoLP(&point);
|
|
|
|
TOcPart* p = GetOcDoc()->GetParts().Locate(point);
|
|
|
|
if (modKeys & MK_CONTROL) {
|
|
if (p)
|
|
p->Open(true); // Ctrl key forces open editing
|
|
}
|
|
else {
|
|
SetSelection(p);
|
|
|
|
if (p && p == GetOcView()->GetActivePart()) { // resync the active flag
|
|
p->Activate(false);
|
|
}
|
|
|
|
GetOcView()->ActivatePart(p); // In-place activation
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set new selection, clear/set handles around objects
|
|
//
|
|
void
|
|
TOleWindow::SetSelection(TOcPart* part)
|
|
{
|
|
if (part == DragPart)
|
|
return;
|
|
|
|
// Invalidate old part
|
|
//
|
|
TOcPartChangeInfo changeInfo(DragPart, invView);
|
|
if (DragPart) {
|
|
DragPart->Select(false);
|
|
DragPart->Activate(false);
|
|
EvOcViewPartInvalid(changeInfo);
|
|
}
|
|
|
|
DragPart = part;
|
|
changeInfo.SetPart(DragPart);
|
|
if (DragPart) {
|
|
part->Select(true); // select this one
|
|
EvOcViewPartInvalid(changeInfo);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create popup menu
|
|
//
|
|
void
|
|
TOleWindow::EvRButtonDown(uint, TPoint& point)
|
|
{
|
|
PRECONDITION(GetOcDoc());
|
|
|
|
// Perform hit test on parts...
|
|
//
|
|
TPoint oldPoint = point;
|
|
TOleClientDC dc(*this);
|
|
dc.DPtoLP(&point);
|
|
|
|
TOcPart* p = GetOcDoc()->GetParts().Locate(point);
|
|
SetSelection(p);
|
|
|
|
if (DragPart) {
|
|
// Create popup menu
|
|
//
|
|
TMenu menu(GetModule()->LoadMenu(IDM_OLEPOPUP), AutoDelete);
|
|
TPopupMenu popMenu(menu.GetSubMenu(0));
|
|
|
|
if (popMenu.GetHandle()) {
|
|
TOcVerb ocVerb;
|
|
TMenu* verbMenu = CreateVerbPopup(ocVerb);
|
|
|
|
string optName = GetModule()->LoadString(IDS_EDITOBJECT);
|
|
string newMenuName(OleStr(ocVerb.TypeName));
|
|
newMenuName += ' ';
|
|
newMenuName += optName;
|
|
popMenu.ModifyMenu(CM_EDITOBJECT, MF_ENABLED | MF_BYCOMMAND | MF_POPUP,
|
|
(uint)verbMenu->GetHandle(), newMenuName.c_str());
|
|
delete verbMenu;
|
|
|
|
// Add the verb menu
|
|
//
|
|
ClientToScreen(oldPoint);
|
|
|
|
// Route commands through main window
|
|
//
|
|
popMenu.TrackPopupMenu(TPM_RIGHTBUTTON, oldPoint, 0, *this);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deactivate active embedded object if any
|
|
//
|
|
bool
|
|
TOleWindow::Deactivate()
|
|
{
|
|
// Deactivate active part, if any
|
|
//
|
|
if (DragPart && DragPart->IsActive()) {
|
|
SetSelection(0);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Select embedded object, point is in logical units
|
|
//
|
|
bool
|
|
TOleWindow::Select(uint, TPoint& point)
|
|
{
|
|
PRECONDITION(GetOcDoc());
|
|
|
|
// If the point is not on the current selection, perform hit test on parts
|
|
// to find & select one
|
|
//
|
|
if (!DragPart || !DragPart->IsVisible(TRect(point, TSize(1,1))))
|
|
SetSelection(GetOcDoc()->GetParts().Locate(point));
|
|
|
|
// If a part is now selected, manipulate it.
|
|
//
|
|
if (DragPart) {
|
|
DragRect = DragPart->GetRect();
|
|
DragRect.right++;
|
|
DragRect.bottom++;
|
|
if (DragPart->IsSelected()) {
|
|
TUIHandle handle(DragRect, TUIHandle::HandlesIn | TUIHandle::Grapples |
|
|
TUIHandle::Framed);
|
|
DragHit = handle.HitTest(point);
|
|
}
|
|
else {
|
|
DragHit = TUIHandle::MidCenter;
|
|
}
|
|
|
|
if (!DragDC)
|
|
DragDC = new TOleClientDC(*this);
|
|
DragDC->DrawFocusRect(DragRect);
|
|
|
|
DragStart = DragPt = point;
|
|
SetCapture();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Check if any embedded object is selected
|
|
//
|
|
void
|
|
TOleWindow::EvLButtonDown(uint modKeys, TPoint& point)
|
|
{
|
|
// Deactivating in-place active object, if any
|
|
//
|
|
if (Deactivate())
|
|
return;
|
|
|
|
// Convert the point to logical unit
|
|
//
|
|
if (!DragDC)
|
|
DragDC = new TOleClientDC(*this);
|
|
|
|
DragDC->DPtoLP(&point);
|
|
Select(modKeys, point);
|
|
}
|
|
|
|
//
|
|
// Is the logical point within the client area?
|
|
//
|
|
bool
|
|
TOleWindow::InClient(TDC& dc, TPoint& point)
|
|
{
|
|
TRect logicalRect = GetClientRect();
|
|
|
|
dc.DPtoLP((TPoint*)&logicalRect, 2);
|
|
return logicalRect.Contains(point);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TOleWindow::EvMouseMove(uint modKeys, TPoint& point)
|
|
{
|
|
if (!DragDC)
|
|
return;
|
|
|
|
// Convert the point to logical unit
|
|
//
|
|
DragDC->DPtoLP(&point);
|
|
|
|
// A MidCenter hit is a move
|
|
//
|
|
if (DragHit == TUIHandle::MidCenter) {
|
|
DragDC->DrawFocusRect(DragRect); // erase old rect
|
|
|
|
// Account for case when the hand is a little shaky and a double click for
|
|
// open editing generates a move msg. as a side-effect
|
|
//
|
|
bool force = ((modKeys & MK_CONTROL) || (::GetKeyState(VK_MENU)&0x8000)) &&
|
|
(abs(point.x-DragStart.x) > DblClkDelta.cx ||
|
|
abs(point.y-DragStart.y) > DblClkDelta.cy);
|
|
|
|
// Start drag & drop if point is outside client, or Ctrl or Alt is pressed
|
|
//
|
|
if (DragPart && (!InClient(*DragDC, point) || force)) {
|
|
TOcDropAction outAction;
|
|
OcApp->Drag(DragPart, daDropCopy | daDropMove | daDropLink, outAction);
|
|
|
|
TOcPartChangeInfo changeInfo(DragPart, invView | invData);
|
|
EvOcViewPartInvalid(changeInfo);
|
|
DragHit = TUIHandle::Outside;
|
|
ReleaseCapture();
|
|
|
|
// Delete the dragged part since it was dragged out
|
|
//
|
|
if (outAction == daDropMove) {
|
|
DragPart->Delete();
|
|
DragPart = 0;
|
|
}
|
|
}
|
|
else {
|
|
TPoint delta = point - DragPt;
|
|
DragRect.Offset(delta.x, delta.y);
|
|
DragDC->DrawFocusRect(DragRect); // draw new rect
|
|
}
|
|
}
|
|
// All other non-outside hits are resizes
|
|
//
|
|
else if (DragHit != TUIHandle::Outside) { // handle
|
|
DragDC->DrawFocusRect(DragRect); // erase old rect
|
|
int dl = (DragHit%3) == 0 ? point.x - DragPt.x : 0;
|
|
int dr = (DragHit%3) == 2 ? point.x - DragPt.x : 0;
|
|
int dt = (DragHit/3) == 0 ? point.y - DragPt.y : 0;
|
|
int db = (DragHit/3) == 2 ? point.y - DragPt.y : 0;
|
|
|
|
// maintain minimum part size
|
|
//
|
|
if ((DragRect.Width() + dr - dl) >= MinWidth) {
|
|
DragRect.left += dl;
|
|
DragRect.right += dr;
|
|
}
|
|
if ((DragRect.Height() + db - dt) >= MinHeight) {
|
|
DragRect.top += dt;
|
|
DragRect.bottom += db;
|
|
}
|
|
|
|
DragDC->DrawFocusRect(DragRect); // draw new rect
|
|
}
|
|
|
|
DragPt = point;
|
|
}
|
|
|
|
void
|
|
TOleWindow::EvLButtonUp(uint /*modKeys*/, TPoint& /*point*/)
|
|
{
|
|
if (DragPart) {
|
|
TOcPartChangeInfo changeInfo(DragPart, invView | invData);
|
|
|
|
// All non-outside hits are moves or resizes
|
|
//
|
|
if (DragHit != TUIHandle::Outside) {
|
|
EvOcViewPartInvalid(changeInfo);
|
|
DragPart->SetPos(DragRect.TopLeft());
|
|
if (DragHit != TUIHandle::MidCenter)
|
|
DragPart->SetSize(DragRect.Size()); // A MidCenter hit is a move only
|
|
EvOcViewPartInvalid(changeInfo);
|
|
}
|
|
InvalidatePart(invView);
|
|
|
|
DragHit = TUIHandle::Outside;
|
|
ReleaseCapture();
|
|
}
|
|
|
|
if (DragDC) {
|
|
delete DragDC;
|
|
DragDC = 0;
|
|
DragRect.SetNull();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let OcView know that the view window has changed sizes
|
|
//
|
|
void
|
|
TOleWindow::EvSize(uint sizeType, TSize& size)
|
|
{
|
|
TWindow::EvSize(sizeType, size);
|
|
OcView->EvResize();
|
|
}
|
|
|
|
//
|
|
// Handle message forwarded from our mdi child frame (if any) to let OcView
|
|
// know that the view window has changed size
|
|
//
|
|
void
|
|
TOleWindow::EvMDIActivate(HWND hWndActivated, HWND /*hWndDeactivated*/)
|
|
{
|
|
OcView->EvActivate(hWndActivated == *Parent);
|
|
}
|
|
|
|
uint
|
|
TOleWindow::EvMouseActivate(HWND topParent, uint /*hitCode*/, uint /*msg*/)
|
|
{
|
|
if (topParent)
|
|
ForwardMessage(topParent);
|
|
|
|
return MA_ACTIVATE;
|
|
}
|
|
|
|
//
|
|
// May need to pass focus to an in-place server if there is one
|
|
//
|
|
void
|
|
TOleWindow::EvSetFocus(HWND hWndLostFocus)
|
|
{
|
|
TWindow::EvSetFocus(hWndLostFocus);
|
|
OcView->EvSetFocus(true); // Maybe active part (if any) wants focus
|
|
}
|
|
|
|
//
|
|
// response method for an incoming WM_VSCROLL message
|
|
//
|
|
void
|
|
TOleWindow::EvHScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
|
|
{
|
|
TWindow::EvHScroll(scrollCode, thumbPos, hWndCtl);
|
|
|
|
InvalidatePart(invView);
|
|
}
|
|
|
|
//
|
|
// response method for an incoming WM_VSCROLL message
|
|
//
|
|
void
|
|
TOleWindow::EvVScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
|
|
{
|
|
TWindow::EvVScroll(scrollCode, thumbPos, hWndCtl);
|
|
|
|
InvalidatePart(invView);
|
|
}
|
|
|
|
//
|
|
// Handle WM_MENUSELECT to provide hint text in the container's status bar
|
|
// based on the menu item id. Treat popup items seperatly and ask them for
|
|
// their ids. Similar to code in TDecoratedFrame.
|
|
//
|
|
void
|
|
TOleWindow::EvMenuSelect(uint menuItemId, uint flags, HMENU hMenu)
|
|
{
|
|
|
|
if (GetOcRemView()) {
|
|
if (flags == 0xFFFF && hMenu == 0) { // menu closing
|
|
GetOcRemView()->SetContainerStatusText("");
|
|
return;
|
|
}
|
|
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 = 0; // display an empty help message
|
|
}
|
|
string text = GetModule()->LoadString(menuItemId);
|
|
GetOcRemView()->SetContainerStatusText(text.c_str());
|
|
}
|
|
else
|
|
TWindow::EvMenuSelect(menuItemId, flags, hMenu);
|
|
}
|
|
|
|
//
|
|
// Handle & sub-dispatch the OC event message.
|
|
//
|
|
LRESULT
|
|
TOleWindow::EvOcEvent(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TEventHandler::TEventInfo eventInfo(WM_OCEVENT, wParam);
|
|
if (Find(eventInfo))
|
|
return Dispatch(eventInfo, wParam, lParam);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Return our frame's title
|
|
//
|
|
const char far*
|
|
TOleWindow::EvOcViewTitle()
|
|
{
|
|
char title[128];
|
|
Parent->GetWindowText(title, sizeof title);
|
|
ContainerName = title;
|
|
|
|
return ContainerName.c_str();
|
|
}
|
|
|
|
//
|
|
// Set our frame's title
|
|
//
|
|
void
|
|
TOleWindow::EvOcViewSetTitle(const char far* title)
|
|
{
|
|
Parent->SetWindowText(title);
|
|
}
|
|
|
|
//
|
|
// Can the server put toolbars in our view? Say no--make him use the app frame
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewBorderSpaceReq(TRect far* /*space*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Can the server put toolbars in our view? Say no--make him use the app frame
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewBorderSpaceSet(TRect far* /*space*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Can the indicated ole object be dropped here? Say yes to everything as a
|
|
// default
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewDrop(TOcDragDrop far& /*ddInfo*/)
|
|
{
|
|
return true; // ok to drop anything, we can take it...
|
|
}
|
|
|
|
//
|
|
// Provide drag UI feedback
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewDrag(TOcDragDrop far& ddInfo)
|
|
{
|
|
TClientDC dc(*this);
|
|
TPen pen(TColor(128, 128, 128), 4, PS_DOT);
|
|
dc.SelectObject(pen);
|
|
dc.SelectStockObject(HOLLOW_BRUSH);
|
|
dc.SetROP2(R2_NOTXORPEN);
|
|
|
|
dc.Rectangle(*ddInfo.Pos);
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Scroll our view window. Update any internal state as needed. This is called
|
|
// when the server is sizing, or a drop interaction is near the edge
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewScroll(TOcScrollDir /*scrollDir*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Convert the part rect into device units
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewGetSiteRect(TRect far* rect)
|
|
{
|
|
TOleClientDC dc(*this);
|
|
|
|
return dc.LPtoDP((TPoint*)rect, 2);
|
|
}
|
|
|
|
//
|
|
// Convert the part rect into logical units
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewSetSiteRect(TRect far* rect)
|
|
{
|
|
TOleClientDC dc(*this);
|
|
|
|
return dc.DPtoLP((TPoint*)rect, 2);
|
|
}
|
|
|
|
//
|
|
// Handle the scaling for server app
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewGetScale(TOcScaleFactor& scaleFactor)
|
|
{
|
|
scaleFactor = Scale;
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Handle the scaling for server app
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewPartActivate(TOcPart& ocPart)
|
|
{
|
|
SetSelection(&ocPart);
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Handle the scaling for server app
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewPasteObject(TOcInitInfo& init)
|
|
{
|
|
TRect rect;
|
|
GetInsertPosition(rect);
|
|
new TOcPart(*GetOcDoc(), init, rect);
|
|
init.ReleaseDataObject();
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Ask server to paint itself in the position and dc provided
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewPaint(TOcViewPaint far& vp)
|
|
{
|
|
// paint according to the view paint structure
|
|
//
|
|
TDC dc(vp.DC);
|
|
Pos = *vp.Pos;
|
|
|
|
// Paint embedded objects
|
|
//
|
|
|
|
bool metafile = dc.GetDeviceCaps(TECHNOLOGY) == DT_METAFILE;
|
|
SetupDC(dc, !metafile);
|
|
|
|
if (vp.Moniker) {
|
|
PaintLink(dc, true, Pos, *vp.Moniker);
|
|
}
|
|
else if (vp.PaintSelection) {
|
|
PaintSelection(dc, true, Pos, vp.UserData);
|
|
}
|
|
else {
|
|
Paint(dc, true, Pos);
|
|
PaintParts(dc, true, Pos, metafile);
|
|
}
|
|
|
|
Pos.SetNull();
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// TOcRemView is going away, disconnect TOleWindow with it so we don't use it
|
|
// later. If this is a remote view, then close the doc too.
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewClose()
|
|
{
|
|
if (IsRemote() && OcDoc)
|
|
OcDoc->Close();
|
|
|
|
OcView = 0;
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Ask server to save itself in the IStorage
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewSavePart(TOcSaveLoad far& /*ocSave*/)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Ask server to load itself from the IStorage
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewLoadPart(TOcSaveLoad far& /*ocLoad*/)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Let container know about the server view size in pixels
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewPartSize(TOcPartSize far& /*size*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Ask container to open an existing document
|
|
// Used for linking from embedding
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewOpenDoc(const char far* /*path*/)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Insert server menu into the composite one
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewInsMenus(TOcMenuDescr far& /*sharedMenu*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Request for server to put up its toolbar. This implementation assume that
|
|
// this server is single use, and the MainWindow's ToolBar is ours to snarf
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewShowTools(TOcToolBarInfo far& tbi)
|
|
{
|
|
TWindow* mainWindow = GetApplication()->GetMainWindow();
|
|
CHECK(mainWindow);
|
|
TWindow* toolBar = mainWindow->ChildWithId(IDW_TOOLBAR);
|
|
if (!toolBar)
|
|
return false;
|
|
tbi.HTopTB = (HWND)*toolBar;
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Get server's color palette
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewGetPalette(LOGPALETTE far* far* /*palette*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Ask server to provide data according to the format in a handle
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewClipData(TOcFormatData far& /*format*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Set format data into server
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewSetData(TOcFormatData far& /*format*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Paint the embedded objects
|
|
//
|
|
bool
|
|
TOleWindow::PaintParts(TDC& dc, bool, TRect&, bool metafile)
|
|
{
|
|
if (!GetOcDoc())
|
|
return false;
|
|
|
|
TRect clientRect;
|
|
TRect logicalRect = GetClientRect();
|
|
|
|
if (IsRemote()) {
|
|
clientRect = GetWindowRect();
|
|
clientRect.Offset(-clientRect.left, -clientRect.top);
|
|
}
|
|
else {
|
|
clientRect = logicalRect;
|
|
}
|
|
|
|
TPoint scrollPos(0, 0);
|
|
|
|
if (!metafile) {
|
|
dc.DPtoLP((TPoint*)&logicalRect, 2);
|
|
}
|
|
else {
|
|
if (Scroller) {
|
|
scrollPos.x = (int)Scroller->XPos;
|
|
scrollPos.y = (int)Scroller->YPos;
|
|
}
|
|
}
|
|
|
|
for (TOcPartCollectionIter i(GetOcDoc()->GetParts()); i; i++) {
|
|
TOcPart& p = *i.Current();
|
|
if (p.IsVisible(logicalRect) || metafile) {
|
|
TRect r = p.GetRect();
|
|
r.Offset(-scrollPos.x, -scrollPos.y);
|
|
p.Draw(dc, r, clientRect, asDefault);
|
|
|
|
if (metafile)
|
|
continue;
|
|
|
|
// Paint selection
|
|
//
|
|
if ((p.IsSelected() || ShowObjects) && r.Width() > 0 && r.Height() > 0) {
|
|
uint handleStyle = p.IsLink() ? TUIHandle::DashFramed : TUIHandle::Framed;
|
|
if (p.IsSelected())
|
|
handleStyle |= TUIHandle::Grapples;
|
|
TUIHandle(r, handleStyle).Paint(dc);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Change the scaling factor
|
|
//
|
|
void
|
|
TOleWindow::SetScale(uint16 percent)
|
|
{
|
|
Scale.SetScale(percent);
|
|
Invalidate();
|
|
}
|
|
|
|
//
|
|
// Get the logical unit per inch for document
|
|
//
|
|
void
|
|
TOleWindow::GetLogPerUnit(TSize& logPerUnit)
|
|
{
|
|
TScreenDC dc;
|
|
|
|
logPerUnit.cx = dc.GetDeviceCaps(LOGPIXELSX);
|
|
logPerUnit.cy = dc.GetDeviceCaps(LOGPIXELSY);
|
|
}
|
|
|
|
//
|
|
// Setup the dc before painting
|
|
//
|
|
void
|
|
TOleWindow::SetupDC(TDC& dc, bool scale)
|
|
{
|
|
dc.SetMapMode(MM_ANISOTROPIC);
|
|
|
|
// Setup window and viewport origin according to scroll amount
|
|
//
|
|
TPoint scrollPos(0, 0);
|
|
if (Scroller) {
|
|
scrollPos.x = (int)Scroller->XPos;
|
|
scrollPos.y = (int)Scroller->YPos;
|
|
}
|
|
|
|
if (!scale) {
|
|
dc.SetWindowOrg(scrollPos);
|
|
return;
|
|
}
|
|
|
|
// Don't scale the scrolling amount
|
|
//
|
|
if (Scale.SiteSize.cx)
|
|
scrollPos.x = (int)(((uint32)scrollPos.x * Scale.PartSize.cx +
|
|
Scale.SiteSize.cx/2) / Scale.SiteSize.cx);
|
|
if (Scale.SiteSize.cy)
|
|
scrollPos.y = (int)(((uint32)scrollPos.y * Scale.PartSize.cy +
|
|
Scale.SiteSize.cy/2) / Scale.SiteSize.cy);
|
|
dc.SetWindowOrg(scrollPos);
|
|
|
|
dc.SetViewportOrg(Pos.TopLeft());
|
|
|
|
// set the window and viewport extaccording to zoom factor
|
|
//
|
|
TSize ext;
|
|
GetLogPerUnit(ext);
|
|
dc.SetWindowExt(ext);
|
|
|
|
ext.cx = dc.GetDeviceCaps(LOGPIXELSX);
|
|
ext.cy = dc.GetDeviceCaps(LOGPIXELSY);
|
|
|
|
if (Scale.PartSize.cx)
|
|
ext.cx = (int)(((uint32)ext.cx * Scale.SiteSize.cx + Scale.PartSize.cx/2) /
|
|
Scale.PartSize.cx);
|
|
if (Scale.PartSize.cy)
|
|
ext.cy = (int)(((uint32)ext.cy * Scale.SiteSize.cy + Scale.PartSize.cy/2) /
|
|
Scale.PartSize.cy);
|
|
dc.SetViewportExt(ext);
|
|
}
|
|
|
|
//
|
|
// response method for an incoming WM_PAINT message
|
|
//
|
|
void
|
|
TOleWindow::EvPaint()
|
|
{
|
|
if (IsFlagSet(wfAlias))
|
|
DefaultProcessing(); // use application-defined wndproc
|
|
|
|
else {
|
|
TPaintDC dc(*this);
|
|
TRect& rect = *(TRect*)&dc.Ps.rcPaint;
|
|
|
|
if (Scroller)
|
|
Scroller->BeginView(dc, rect);
|
|
|
|
bool metafile = dc.GetDeviceCaps(TECHNOLOGY) == DT_METAFILE;
|
|
SetupDC(dc, !metafile);
|
|
Paint(dc, dc.Ps.fErase, rect);
|
|
PaintParts(dc, dc.Ps.fErase, rect, metafile);
|
|
|
|
if (Scroller)
|
|
Scroller->EndView();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Notify the active view of part data changes
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewPartInvalid(TOcPartChangeInfo& changeInfo)
|
|
{
|
|
// Our document is now dirty...
|
|
|
|
// Reflect the change in part in other (non-active) views
|
|
//
|
|
TRect rect(changeInfo.GetPart()->GetRect());
|
|
rect.right++;
|
|
rect.bottom++;
|
|
TOleClientDC dc(*this);
|
|
dc.LPtoDP((TPoint*)&rect, 2);
|
|
|
|
InvalidateRect(rect); // Multiview support to be done in derived classes
|
|
|
|
// Notify container if this is an intermediate container
|
|
//
|
|
InvalidatePart((TOcInvalidate)changeInfo.GetType());
|
|
|
|
return true; // stop further processing by OCF
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TPopupMenu*
|
|
TOleWindow::CreateVerbPopup(const TOcVerb& ocVerb)
|
|
{
|
|
TPopupMenu* verbMenu = new TPopupMenu(NoAutoDelete);
|
|
while (DragPart->EnumVerbs(ocVerb)) {
|
|
verbMenu->AppendMenu(MF_STRING|MF_ENABLED,
|
|
(uint)CM_EDITFIRSTVERB + ocVerb.VerbIndex,
|
|
(const char far*)OleStr(ocVerb.VerbName));
|
|
}
|
|
|
|
verbMenu->AppendMenu(MF_SEPARATOR, 0, 0);
|
|
string optName = GetModule()->LoadString(IDS_EDITCONVERT);
|
|
verbMenu->AppendMenu(MF_STRING, CM_EDITCONVERT, optName.c_str());
|
|
|
|
return verbMenu;
|
|
}
|
|
|
|
//
|
|
// Execute a verb pertaining to the selected object
|
|
//
|
|
void
|
|
TOleWindow::EvDoVerb(uint whichVerb)
|
|
{
|
|
DragPart->DoVerb(whichVerb);
|
|
}
|
|
|
|
//
|
|
// Attach this view back to its owl parent for either open editing, or
|
|
// mearly inplace de-activating
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewAttachWindow(bool attach)
|
|
{
|
|
TOleFrame* mainWindow = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(),
|
|
TOleFrame);
|
|
if (!mainWindow)
|
|
return false; // server app is shutting down
|
|
|
|
if (attach) {
|
|
if (IsOpenEditing()) {
|
|
// Derived class needs to managed setting up frame differently, like
|
|
// for MDI etc.
|
|
//
|
|
mainWindow->SetClientWindow(this);
|
|
}
|
|
}
|
|
else {
|
|
if (IsOpenEditing() && Parent != mainWindow)
|
|
Parent->PostMessage(WM_CLOSE);
|
|
SetParent(mainWindow->GetRemViewBucket()); // simple reparent
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Perform the action indentified by verb
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewDoVerb(uint /*verb*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Shut down the associated OCF partners if possible
|
|
//
|
|
bool
|
|
TOleWindow::OleShutDown()
|
|
{
|
|
if (IsRemote()) {
|
|
TOcRemView* ocRemView = GetOcRemView();
|
|
if (IsOpenEditing())
|
|
ocRemView->Disconnect();
|
|
}
|
|
else {
|
|
if (OcView)
|
|
OcView->EvClose();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Perform normal CleanupWindow, plus let the OcView object know we have closed
|
|
//
|
|
void
|
|
TOleWindow::CleanupWindow()
|
|
{
|
|
TOleFrame* mainWindow = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(),
|
|
TOleFrame);
|
|
|
|
if (mainWindow)
|
|
mainWindow->OleViewClosing(true);
|
|
OleShutDown();
|
|
if (mainWindow)
|
|
mainWindow->OleViewClosing(false);
|
|
TWindow::CleanupWindow();
|
|
}
|
|
|
|
static void
|
|
DoIdleAction(TWindow* win, void* idleCount)
|
|
{
|
|
win->IdleAction(*(long*)idleCount);
|
|
}
|
|
|
|
//
|
|
// TOleWindow processes idle action occurs once per block of messages
|
|
//
|
|
bool
|
|
TOleWindow::IdleAction(long idleCount)
|
|
{
|
|
if (idleCount == 0) {
|
|
// give child windows an opportunity to do any idle processing
|
|
//
|
|
ForEach(DoIdleAction, &idleCount);
|
|
}
|
|
return false; // we don't need any more time for now
|
|
}
|
|
|
|
//
|
|
// Handle the scaling for server app
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewSetScale(TOcScaleFactor& scaleFactor)
|
|
{
|
|
Scale = scaleFactor;
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Find the item name for whole doc or selection
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewGetItemName(TOcItemName& /*item*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Linking Spport
|
|
//
|
|
|
|
//
|
|
// Establish link with whole doc or selection
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewSetLink(TOcLinkView& /*view*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Break link with whole doc or selection
|
|
//
|
|
bool
|
|
TOleWindow::EvOcViewBreakLink(TOcLinkView& /*view*/)
|
|
{
|
|
return false;
|
|
}
|