//---------------------------------------------------------------------------- // ObjectWindows // (C) Copyright 1992, 1994 by Borland International, All Rights Reserved // // Implementation of TStatusBar //---------------------------------------------------------------------------- #include #include #include // // Local class to manage the mode indicator strings // class TModeStrings { public: // constructor TModeStrings() : ModeBuff(0), ModeStrings(0), NumModes(0) {} ~TModeStrings() { delete [] ModeBuff; delete [] ModeStrings; } void Init(TModule* module, uint16 resId, const char* defaultModes); // access int Count() const { return NumModes; } const char* operator [](int i) const { return ModeStrings[i]; } private: int NumModes; char* ModeBuff; char** 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, const char* defaultModes) { if (!ModeStrings) { string modeResString(module->LoadString(resId)); ModeBuff = strnewdup(modeResString.length() > 0 ? modeResString.c_str() : defaultModes); NumModes = 1; for (char* p = ModeBuff; *p; p++) if (*p == '|') { *p = 0; NumModes++; } typedef char* pchar; ModeStrings = new pchar[NumModes]; p = ModeBuff; for (int i = 0; i < NumModes; i++) { ModeStrings[i] = p; p += strlen(p) + 1; } } } // // Static mode string object, & default mode indicator strings // static TModeStrings ModeOnStrings; static TModeStrings ModeOffStrings; static char DefOnModes[] = "EXT|CAPS|NUM|SCRL|OVR|REC"; static char DefOffModes[] = " | | | | | "; IMPLEMENT_CASTABLE(TStatusBar); 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; ModeOnStrings.Init(GetModule(), IDS_MODES, DefOnModes); ModeOffStrings.Init(GetModule(), IDS_MODESOFF, DefOffModes); 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::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 = Margins.Right = LayoutUnitsToPixels(4); Margins.Top = Margins.Bottom = GetSystemMetrics(SM_CYBORDER); break; case TGadget::Plain: Margins.Units = TMargins::BorderUnits; Margins.Left = Margins.Top = Margins.Right = Margins.Bottom = -1; 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 < ModeOnStrings.Count(); i++) if (ModeIndicators & (1 << i)) { const int SMALL_MARGIN = 1; int maxLen = max(strlen(ModeOnStrings[i]), strlen(ModeOffStrings[i])); TTextGadget* gadget = new TTextGadget(0, BorderStyle, TTextGadget::Left, maxLen, ModeOffStrings[i]); TMargins margins = gadget->GetMargins(); // // use small left and right margins // margins.Left = margins.Right = SMALL_MARGIN; gadget->SetMargins(margins); // // turn off shrink wrapping for the width and choose a width that is // custom fit for the string // gadget->SetShrinkWrap(false, true); TMessageBar::Insert(*gadget); TSize onExtent; dc.GetTextExtent(ModeOnStrings[i], strlen(ModeOnStrings[i]), onExtent); TSize offExtent; dc.GetTextExtent(ModeOffStrings[i], strlen(ModeOffStrings[i]), offExtent); TSize extent(max(onExtent.cx, offExtent.cx), onExtent.cy); int left, top, right, bottom; gadget->GetOuterSizes(left, right, top, bottom); extent.cx += left + right; gadget->SetSize(extent); NumModeIndicators++; } } 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; } // // // void TStatusBar::PositionGadget(TGadget*, TGadget* next, TPoint& origin) { int cxBorder = GetSystemMetrics(SM_CXBORDER); if (BorderStyle == TGadget::Plain) origin.x -= cxBorder; // overlap the borders // // 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; } } // // insert a gadget. default placement is just after the gadget to the left of // the status mode indicators // void TStatusBar::Insert(TGadget& gadget, TPlacement placement, TGadget* sibling) { gadget.SetBorderStyle(BorderStyle); if (!sibling) sibling = operator[](NumGadgets - NumModeIndicators - 1); TMessageBar::Insert(gadget, placement, sibling); } // // return gadget at a given index, except mode indicator gadgets // TGadget* TStatusBar::operator [](uint index) { PRECONDITION(index < NumGadgets - NumModeIndicators); for (TGadget* g = Gadgets; index > 0; index--) g = g->NextGadget(); return g; } // // Get the text gadget & the mode string associated with a mode indicator // bool TStatusBar::GetGadgetAndStrings(TModeIndicator mode, TTextGadget*& gadget, const char*& strOn, const char*& strOff) { if ((ModeIndicators & mode) == 0) { return false; // tracing } else { uint slot = NumGadgets - 1; for (int index = ModeOnStrings.Count() - 1; (1 << index) > mode; index--) if (ModeIndicators & (1 << index)) slot--; strOn = ModeOnStrings[index]; strOff = ModeOffStrings[index]; for (gadget = (TTextGadget*)Gadgets; slot > 0; slot--) gadget = (TTextGadget*)gadget->NextGadget(); return true; } } void TStatusBar::ToggleModeIndicator(TModeIndicator mode) { SetModeIndicator(mode, !GetModeIndicator(mode)); } void TStatusBar::SetModeIndicator(TModeIndicator mode, bool on) { TTextGadget* gadget; const char* strOn; const char* strOff; if (GetGadgetAndStrings(mode, gadget, strOn, strOff)) gadget->SetText(on ? strOn : strOff); if (on) ModeIndicatorState |= mode; else ModeIndicatorState &= ~mode; } bool TStatusBar::PreProcessMsg(MSG& msg) { if (msg.message == WM_KEYDOWN) { switch (msg.wParam) { case VK_SCROLL: if (ModeIndicators & ScrollLock) { //ScrollLockModeChange(); ToggleModeIndicator(ScrollLock); } break; case VK_INSERT: if (ModeIndicators & Overtype) { // // Skip if CTRL+INS or SHIFT+INS // if (((::GetKeyState(VK_CONTROL) & 0x8000) == 0) && ((::GetKeyState(VK_SHIFT) & 0x8000) == 0)) //OvertypeModeChange(); ToggleModeIndicator(Overtype); } break; case VK_CAPITAL: if (ModeIndicators & CapsLock) ToggleModeIndicator(CapsLock); break; case VK_NUMLOCK: if (ModeIndicators & NumLock) ToggleModeIndicator(NumLock); break; } } return false; } // // Make sure that we are in sync with the physical KB indicators // bool TStatusBar::IdleAction(long idleCount) { if (idleCount == 0) { if ((::GetKeyState(VK_SCROLL) & 0x0001) != GetModeIndicator(ScrollLock)) ToggleModeIndicator(ScrollLock); if ((::GetKeyState(VK_CAPITAL) & 0x0001) != GetModeIndicator(CapsLock)) ToggleModeIndicator(CapsLock); if ((::GetKeyState(VK_NUMLOCK) & 0x0001) != GetModeIndicator(NumLock)) ToggleModeIndicator(NumLock); } return TMessageBar::IdleAction(idleCount); }