//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TStatusBar
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/defs.h>
#include <owl/statusba.h>
#include <owl/modegad.h>
#include <owl/uimetric.h>
#include <owl/statusba.rh>
#include <owl/layoutwi.h>
namespace owl {
OWL_DIAGINFO;
//
// Local class to manage the mode indicator strings
//
class TModeStrings {
public:
// Constructor
//
TModeStrings() : NumModes(0), ModeBuff(0), ModeStrings(0) {}
~TModeStrings()
{
delete[] ModeBuff;
delete[] ModeStrings;
}
void Init(TModule* module, uint16 resId, LPCTSTR defaultModes);
// Accessors
int Count() const { return NumModes; }
LPCTSTR operator [](int i) const { return ModeStrings[i]; }
private:
int NumModes;
tchar* ModeBuff;
tchar** ModeStrings;
};
//
// Gets the mode string array from a single resource string, like:
// "EXT|CAPS|NUM|SCRL|OVR|REC"
// using the provided default string if resource not found.
//
void
TModeStrings::Init(TModule* module, uint16 resId, LPCTSTR defaultModes)
{
if (!ModeStrings) {
tstring modeResString(module->LoadString(resId));
ModeBuff = strnewdup(modeResString.length() > 0 ?
modeResString.c_str() :
defaultModes);
NumModes = 1;
for (TCharIterator<tchar> i(ModeBuff); ; i++) {
if (!*i.Current())
break;
if (*i.Current() == _T('|')) {
*i.Current() = 0;
NumModes++;
}
}
typedef tchar* pchar;
ModeStrings = new pchar[NumModes];
tchar* p = ModeBuff;
for (int j = 0; j < NumModes; j++) {
ModeStrings[j] = p;
p += ::_tcslen(p) + 1;
}
}
}
//
// Static mode string object, & default mode indicator strings
//
static tchar DefOnModes[] = _T("EXT|CAPS|NUM|SCRL|OVR|REC");
static TModeStrings&
GetModeOnStrings()
{
static TModeStrings ModeOnStrings;
return ModeOnStrings;
}
static int VkKeys[] = {
0,
VK_CAPITAL,
VK_NUMLOCK,
VK_SCROLL,
VK_INSERT,
0
};
static int GadgetIds[] = {
IDG_STATUS_EXT,
IDG_STATUS_CAPS,
IDG_STATUS_NUM,
IDG_STATUS_SCRL,
IDG_STATUS_OVR,
IDG_STATUS_REC
};
//----------------------------------------------------------------------------
DEFINE_RESPONSE_TABLE1(TStatusBar, TMessageBar)
EV_WM_NCHITTEST,
EV_OWLFRAMESIZE,
END_RESPONSE_TABLE;
//
/// Constructs a TStatusBar object in the parent window and creates any new gadgets
/// and mode indicator gadgets. Sets BorderStyle to borderStyle, ModeIndicators to
/// modeIndicators, and NumModeIndicators to 0. borderStyle can be any one of the
/// values of the BorderStyle enum (for example, Plain, Raised, Recessed, or
/// Embossed). The parameter mode indicators can be one of the values of the
/// TModeIndicator enum, such as CapsLock, NumLock, ScrollLock, or Overtype. The
/// parameter font points to a font object that contains the type of fonts used for
/// the gadget window. The parameter, module, which defaults to 0, is passed to the
/// base TWindow's constructor in the module parameter. Sets the values of the
/// margins and borders depending on whether the gadget is raised, recessed, or
/// plain.
//
TStatusBar::TStatusBar(TWindow* parent,
TGadget::TBorderStyle borderStyle,
uint modeIndicators,
TFont* font,
TModule* module)
:
TMessageBar(parent, font, module)
{
BorderStyle = borderStyle;
ModeIndicators = modeIndicators;
ModeIndicatorState = 0;
NumModeIndicators = 0;
WideHintText = true;
GetModeOnStrings().Init(GetModule(), IDS_MODES, DefOnModes);
// Statusbars should always stay flush to the decorated frame's border
//
SetFlag(wfInsertAtEdge);
if (BorderStyle == TGadget::Plain || BorderStyle == TGadget::Embossed)
HighlightLine = false;
else
Spacing.Value = 2; // Hilight line + 1/4-em margin on raised & recessed
switch (BorderStyle) {
case TGadget::None:
case TGadget::Embossed:
case TGadget::Grooved:
case TGadget::ButtonUp:
case TGadget::ButtonDn:
case TGadget::WndRaised:
case TGadget::WndRecessed:
case TGadget::WellSet:
break;
case TGadget::Raised:
case TGadget::Recessed:
// We want one border height along the top and bottom and 1/2 an em quad
// along the left and right so we will set pixels and compute the lengths
// ourselves
//
Margins.Units = TMargins::Pixels;
Margins.Left = LayoutUnitsToPixels(4);
Margins.Right = LayoutUnitsToPixels(4);
// The UI for a sizegrip isn't available in 16-bit Windows
//
if (ModeIndicators & SizeGrip)
Margins.Right = LayoutUnitsToPixels(1);
Margins.Top = Margins.Bottom = TUIMetric::CyBorder;
break;
case TGadget::Plain:
Margins.Units = TMargins::BorderUnits;
Margins.Left = Margins.Top = Margins.Right = Margins.Bottom = -1;
break;
default: //JJH added empty default construct
break;
}
Gadgets->SetBorderStyle(BorderStyle); // Set border style for first gadget
// Create text gadgets for any mode indicators the user requested,
// using provided border style.
//
TScreenDC dc;
dc.SelectObject(*Font);
for (int i = 0; i < GetModeOnStrings().Count(); i++)
if (ModeIndicators & (1 << i)) {
TTextGadget* gadget;
if (owl::VkKeys[i] == 0) {
gadget = new TTextGadget(GadgetIds[i], BorderStyle, TTextGadget::Left,
lstrlen(GetModeOnStrings()[i]),
GetModeOnStrings()[i], 0);
gadget->SetEnabled(false);
}
else
gadget = new TModeGadget(VkKeys[i], GetModeOnStrings()[i],
GadgetIds[i],
BorderStyle, TModeGadget::Center, 0);
TMargins margins = gadget->GetMargins();
// Use small left and right margins
//
margins.Left = margins.Right = 2;
gadget->SetMargins(margins);
TMessageBar::Insert(*gadget);
NumModeIndicators++;
}
if (ModeIndicators & SizeGrip) {
InsertSizeGrip();
}
}
//
/// Create a size grip and place it on the status bar.
/// (Size grips are not available on 16-bit Windows.)
//
void
TStatusBar::InsertSizeGrip()
{
PRECONDITION(
TYPESAFE_DOWNCAST(GadgetWithId(IDG_SIZEGRIP), TSizeGripGadget) == 0);
TSizeGripGadget* gadget = new TSizeGripGadget;
TMessageBar::Insert(*gadget, TGadgetList::After);
TRect bounds = gadget->GetBounds();
bounds.Inflate(1, 1);
gadget->SetBounds(bounds);
NumModeIndicators++;
}
//
/// Determines if a given gadget is being used as a mode indicator
//
bool
TStatusBar::IsModeIndicator(TGadget* gadget)
{
int nonModeIndicators = NumGadgets - NumModeIndicators;
TGadget* g = Gadgets;
for (int i = 0; i < nonModeIndicators; i++) {
if (gadget == g)
return false;
g = g->NextGadget();
}
return true;
}
//
/// Determines the position of the new gadget in relation to any previously existing
/// gadgets and uses the Pixels, LayoutUnits, and BorderUnits fields of TMargins to
/// determine the amount of spacing to leave between the mode indicators.
//
void
TStatusBar::PositionGadget(TGadget*, TGadget* next, TPoint& origin)
{
int cxBorder = TUIMetric::CxBorder;
if (BorderStyle == TGadget::Plain)
origin.x -= cxBorder; // overlap the borders
TSizeGripGadget* gadget = TYPESAFE_DOWNCAST(next, TSizeGripGadget);
if (gadget)
return;
// Leave extra spacing between the mode indicators
//
if (IsModeIndicator(next))
switch (Spacing.Units) {
case TMargins::Pixels:
origin.x += Spacing.Value;
break;
case TMargins::LayoutUnits:
origin.x += LayoutUnitsToPixels(Spacing.Value);
break;
case TMargins::BorderUnits:
origin.x += Spacing.Value * cxBorder;
break;
}
}
//
/// Inserts the gadget (objects derived from class TGadget) in the status bar. By
/// default, the new gadget is placed just after any existing gadgets and to the
/// left of the status mode indicators. For example, you can insert a painting tool
/// or a happy face that activates a recorded macro.
//
void
TStatusBar::Insert(TGadget& gadget, TPlacement placement, TGadget* sibling)
{
gadget.SetBorderStyle(BorderStyle);
if (!sibling)
sibling = operator[](NumGadgets - NumModeIndicators - 1);
TMessageBar::Insert(gadget, placement, sibling);
}
//
/// Overriden to allow hint text to be displayed in the text gadget.
/// If WideHintText is requested then the hint covers the whole gadget window.
/// Otherwise it is displayed within the text gadget.
//
void
TStatusBar::SetHintText(LPCTSTR text)
{
if (WideHintText)
TMessageBar::SetHintText(text);
else
{
tstring s = text ? tstring(text) : tstring();
SetText(s);
}
}
//
/// Get the text gadget & the mode string associated with a mode indicator
//
bool
TStatusBar::GetGadgetAndStrings(TModeIndicator mode, TTextGadget*& gadget,
LPCTSTR& strOn)
{
if ((ModeIndicators & mode) == 0) {
return false; // tracing
}
else {
uint slot = NumGadgets - 1;
int index;
for (index = GetModeOnStrings().Count() - 1; (1 << index) > mode; index--)
if (ModeIndicators & (1 << index))
slot--;
strOn = GetModeOnStrings()[index];
for (gadget = (TTextGadget*)Gadgets; slot > 0; slot--)
gadget = (TTextGadget*)gadget->NextGadget();
return true;
}
}
//
/// Toggles the ModeIndicator.
//
void
TStatusBar::ToggleModeIndicator(TModeIndicator mode)
{
SetModeIndicator(mode, !GetModeIndicator(mode));
}
//
/// Sets TModeIndicator to a given text gadget and set the status (on, by default)
/// of the mode indicator. For the mode indicator to appear on the status bar, you
/// must specify the mode when the window is constructed.
//
void
TStatusBar::SetModeIndicator(TModeIndicator mode, bool on)
{
TTextGadget* gadget;
const tchar* strOn;
if (GetGadgetAndStrings(mode, gadget, strOn)) {
gadget->SetEnabled(on);
}
if (on)
ModeIndicatorState |= mode;
else
ModeIndicatorState &= ~mode;
}
//
/// If the status bar has a size grip gadget and the mouse is over the gadget,
/// simulates resizing of the frame.
//
uint
TStatusBar::EvNCHitTest(const TPoint& point)
{
uint retVal = TMessageBar::EvNCHitTest(point);
TSizeGripGadget* grip = TYPESAFE_DOWNCAST(GadgetWithId(IDG_SIZEGRIP), TSizeGripGadget);
if (grip && grip->GetEnabled()) {
TRect rect = grip->GetBounds();
rect.right += 1;
rect.bottom += 1;
TPoint p = MapScreenToClient(point);
if (rect.Contains(p)) ///BGM use TGadget::PtIn here (so IsVisible() will be checked)
retVal = HTBOTTOMRIGHT;
}
return retVal;
}
//
/// If the frame window that owns the status bar maximizes,
/// then remove the size grip. (Otherwise, the size grip
/// remains uselessly and confusingly active in a maximized window.)
//
void
TStatusBar::EvOwlFrameSize(uint sizeType, const TSize&)
{
TSizeGripGadget* grip = TYPESAFE_DOWNCAST(GadgetWithId(IDG_SIZEGRIP),
TSizeGripGadget);
// If the window was maximized and has a grip, then remove the grip.
//
bool callresize = false;
if (sizeType==SIZE_MAXIMIZED) {
if (grip) {
Remove(*grip);
delete grip;
NumModeIndicators--;
LayoutSession();
callresize = true;
}
}
// If the window was restored and if it is supposed to have a size grip
// but the grip isn't there, then provide a new grip.
//
else if (sizeType == SIZE_RESTORED) {
if (!grip && (GetModeIndicators() & SizeGrip)) {
InsertSizeGrip();
LayoutSession();
callresize = true;
}
}
if(callresize){
TLayoutWindow* window = TYPESAFE_DOWNCAST(GetParentO(), TLayoutWindow);
if(window)
window->Layout();
}
}
} // OWL namespace
/* ========================================================================== */
↑ V302 Member operator[] of 'TModeStrings' class has a 32-bit type argument. Use memsize-type here.
↑ V656 Variables 'Margins.Left', 'Margins.Right' are initialized through the call to the same function. It's probably an error or un-optimized code. Consider inspecting the 'LayoutUnitsToPixels(4)' expression. Check lines: 170, 171.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.