// ****************************************************************************
// Copyright (C) 1998 by Dieter Windau
// All rights reserved
//
// gadgdesc.cpp: implementation file
// Version: 1.5
// Date: 08.11.1998
// Author: Dieter Windau
//
// Freeware OWL classes that extents the dockable and gadget system
//
// You are free to use/modify this code but leave this header intact.
// May not be sold for profit.
//
// Tested with Borland C++ 5.02, OWL 5.02, OWL6 patch #3 and with Windows
// NT 4.0 SP3 but I think the class should work with Windows 95 too.
// This file is provided "as is" with no expressed or implied warranty.
// Use at your own risk.
//
// This package contains many classes and source that are based on other OWL
// developers work. Very special thanks to Alan Chambers, Christopher Kohlhoff,
// Jo Parrello, Mark Hatsell, Michael Mogensen and Yura Bidus
//
// Please send me bug reports, bug fixes, enhancements, requests, etc., and
// I'll try to keep this in next versions:
// EMail: dieter.windau@usa.net
// Web: http://members.aol.com/softengage/index.htm
//
// ****************************************************************************
#include <owlext\pch.h>
#pragma hdrstop
#include <owl/bitmapga.h>
#include <owl/menugadg.h>
#include <owlext/gadgdesc.h>
#include <owlext/gadgetex.h>
DIAG_DEFINE_GROUP(GadgetDesc, 1, 0);
using namespace owl;
namespace OwlExt {
TGadgetDescriptors* GadgetDescriptors = 0;
// ******************** TGadgetDesc *******************************************
TGadgetDesc::TGadgetDesc(TType type,
int id,
uint attr)
{
Type = type;
Id = id;
Attr = attr;
}
// ******************** TInvisibleGadgetDec ***********************************
TInvisibleGadgetDesc::TInvisibleGadgetDesc():
TGadgetDesc(InvisibleGadgetDesc, CM_INVISIBLEGADGET, GADG_NOOPERATION)
{
}
TGadget* TInvisibleGadgetDesc::ConstructGadget()
{
return new TInvisibleGadgetEx();
}
// ******************** TButtonGadgetDesc *************************************
TButtonGadgetDesc::TButtonGadgetDesc(uint32 bmpResId,
int id,
TButtonGadget::TType buttonGadgetType,
bool enabled,
TButtonGadget::TState buttonGadgetState,
bool sharedGlyph,
uint attr):
TGadgetDesc(ButtonGadgetDesc, id, attr)
{
PRECONDITION (Id);
BmpResId = bmpResId;
ButtonGadgetType = buttonGadgetType;
Enabled = enabled;
ButtonGadgetState = buttonGadgetState;
SharedGlyph = sharedGlyph;
}
TGadget* TButtonGadgetDesc::ConstructGadget()
{
return new TButtonGadgetEx(BmpResId, Id, ButtonGadgetType, Enabled,
ButtonGadgetState, SharedGlyph);
}
// ******************** TButtonTextGadgetDesc *********************************
TButtonTextGadgetDesc::TButtonTextGadgetDesc(
LPCTSTR text,
TDisplayType disptype,
uint32 bmpResId,
int id,
TButtonGadget::TType buttonGadgetType,
bool enabled,
TButtonGadget::TState buttonGadgetState,
bool sharedGlyph,
uint attr):
TButtonGadgetDesc(bmpResId, id, buttonGadgetType,
enabled, buttonGadgetState, sharedGlyph, attr)
{
Type = ButtonTextGadgetDesc;
if (text)
Text = text;
else
Text = TEXT("");
DispType = disptype;
}
TGadget* TButtonTextGadgetDesc::ConstructGadget()
{
return new TButtonTextGadgetEx(Text.c_str(), DispType, BmpResId, Id,
ButtonGadgetType, Enabled, ButtonGadgetState, SharedGlyph);
}
// ******************** TMenuButtonGadgetDesc *********************************
TMenuButtonGadgetDesc::TMenuButtonGadgetDesc(
TPopupType popupType,
HMENU hmenu,
TWindow* cmdTarget,
LPCTSTR text,
TDisplayType disptype,
uint32 bmpResId,
int id,
TButtonGadget::TType buttonGadgetType,
bool enabled,
TButtonGadget::TState buttonGadgetState,
bool sharedGlyph,
uint attr):
TButtonTextGadgetDesc(text, disptype, bmpResId, id,
buttonGadgetType, enabled, buttonGadgetState, sharedGlyph, attr)
{
Type = MenuButtonGadgetDesc;
PopupType = popupType;
hMenu = hmenu;
CmdTarget = cmdTarget;
}
TGadget* TMenuButtonGadgetDesc::ConstructGadget()
{
return new TMenuButtonGadgetEx(PopupType, hMenu, CmdTarget, Text.c_str(),
DispType, BmpResId, Id, ButtonGadgetType, Enabled, ButtonGadgetState,
SharedGlyph);
}
// ******************** TRecentFilesGadgetDesc ********************************
TRecentFilesGadgetDesc::TRecentFilesGadgetDesc(
LPCTSTR text,
TDisplayType disptype,
uint32 bmpResId,
int id,
TButtonGadget::TType buttonGadgetType,
bool enabled,
TButtonGadget::TState buttonGadgetState,
bool sharedGlyph,
uint attr):
TButtonTextGadgetDesc(text, disptype, bmpResId, id,
buttonGadgetType, enabled, buttonGadgetState, sharedGlyph, attr)
{
Type = RecentFilesGadgetDesc;
}
TGadget* TRecentFilesGadgetDesc::ConstructGadget()
{
return new TRecentFilesGadgetEx(Text.c_str(), DispType, BmpResId, Id,
ButtonGadgetType, Enabled, ButtonGadgetState, SharedGlyph);
}
// ******************** TColorButtonGadgetDesc ********************************
TColorButtonGadgetDesc::TColorButtonGadgetDesc(
TPopupType popupType,
TColorPickerData& data,
TColor startColorSel,
TRect* fillRect,
TWindow* parentWindow,
LPCTSTR text,
TDisplayType disptype,
uint32 bmpResId,
int id,
TButtonGadget::TType buttonGadgetType,
bool enabled,
TButtonGadget::TState buttonGadgetState,
bool sharedGlyph,
uint attr):
TButtonTextGadgetDesc(text, disptype, bmpResId, id,
buttonGadgetType, enabled, buttonGadgetState, sharedGlyph, attr),
Data(data)
{
Type = ColorButtonGadgetDesc;
PopupType = popupType;
StartColorSel = startColorSel;
FillRect = fillRect;
ParentWindow = parentWindow;
}
TGadget* TColorButtonGadgetDesc::ConstructGadget()
{
return new TColorButtonGadgetEx(PopupType, Data, StartColorSel,
FillRect, ParentWindow, Text.c_str(), DispType, BmpResId, Id,
ButtonGadgetType, Enabled, ButtonGadgetState, SharedGlyph);
}
// ******************** TSeparatorGadgetDesc **********************************
TSeparatorGadgetDesc::TSeparatorGadgetDesc(int size,
int id):
TGadgetDesc(SeparatorGadgetDesc, id, GADG_NOOPERATION)
{
Size = size;
}
TGadget* TSeparatorGadgetDesc::ConstructGadget()
{
return new TSeparatorGadget(Size, Id, false);
}
// ******************** TControlGadgetExDesc ************************************
TControlGadgetDesc::TControlGadgetDesc(TWindow& control,
TGadget::TBorderStyle gadgetBorderStyle,
uint attr):
TGadgetDesc(ControlGadgetDesc, control.GetId(), attr)
{
PRECONDITION (Id);
CHECK (Id != CM_INVISIBLEGADGET);
Control = &control;
GadgetBorderStyle = gadgetBorderStyle;
Count = 0;
}
TControlGadgetDesc::~TControlGadgetDesc()
{
if (Count == 0) {
if (Control->GetHandle())
Control->Destroy(0);
delete Control;
}
}
TGadget* TControlGadgetDesc::ConstructGadget()
{
PRECONDITION(Control);
return new TControlGadgetEx(*Control, GadgetBorderStyle);
}
// ******************** TTextGadgetDesc ***************************************
TTextGadgetDesc::TTextGadgetDesc(int id,
TGadget::TBorderStyle gadgetBorderStyle,
TTextGadget::TAlign textGadgetAlign,
uint numChars,
LPCTSTR text,
uint attr):
TGadgetDesc(TextGadgetDesc, id, attr)
{
PRECONDITION (Id);
CHECK (Id != CM_INVISIBLEGADGET);
GadgetBorderStyle = gadgetBorderStyle;
TextGadgetAlign = textGadgetAlign;
NumChars = numChars;
Text = text;
}
TGadget* TTextGadgetDesc::ConstructGadget()
{
return new TTextGadget(Id, GadgetBorderStyle, TextGadgetAlign,
NumChars, Text.c_str());
}
// ******************** TMenuGadgetDesc ***************************************
TMenuGadgetDesc::TMenuGadgetDesc(TMenu* menu,
TWindow* window,
int id,
TGadget::TBorderStyle gadgetBorderStyle,
LPCTSTR text,
TFont* font,
uint attr):
TGadgetDesc(MenuGadgetDesc, id, attr)
{
PRECONDITION (Id);
CHECK (Id != CM_INVISIBLEGADGET);
Menu = menu;
Window = window;
GadgetBorderStyle = gadgetBorderStyle;
Text = text;
Font = font ? font : new TGadgetWindowFont;
}
TMenuGadgetDesc::~TMenuGadgetDesc()
{
delete Font;
}
TGadget* TMenuGadgetDesc::ConstructGadget()
{
return new TMenuGadget(*Menu, Window, Id, GadgetBorderStyle,
(LPTSTR)Text.c_str(), new TFont(*Font));
}
// ******************** TTimeGadgetDesc ***************************************
TTimeGadgetDesc::TTimeGadgetDesc(TTimeGadget::TGetTimeFunc timeFunc,
int id,
TGadget::TBorderStyle gadgetBorderStyle,
TTextGadget::TAlign textGadgetAlign,
uint numChars,
LPCTSTR text,
TFont* font,
uint attr):
TTextGadgetDesc(id, gadgetBorderStyle, textGadgetAlign, numChars, text, attr)
{
TimeFunc = timeFunc;
Type = TimeGadgetDesc;
Font = font ? font : new TGadgetWindowFont;
}
TTimeGadgetDesc::~TTimeGadgetDesc()
{
delete Font;
}
TGadget* TTimeGadgetDesc::ConstructGadget()
{
return new TTimeGadget(TimeFunc, Id, GadgetBorderStyle,
TextGadgetAlign, NumChars, Text.c_str(), new TFont(*Font));
}
// ******************** TBitmapGadgetDesc *************************************
TBitmapGadgetDesc::TBitmapGadgetDesc(TResId imageResIdOrIndex,
int id,
TGadget::TBorderStyle gadgetBorderStyle,
int numImages,
int startImage,
bool sharedCels,
uint attr):
TGadgetDesc(BitmapGadgetDesc, id, attr)
{
PRECONDITION (Id);
CHECK (Id != CM_INVISIBLEGADGET);
ImageResIdOrIndex = imageResIdOrIndex;
GadgetBorderStyle = gadgetBorderStyle;
NumImages = numImages;
StartImage = startImage;
SharedCels = sharedCels;
}
TGadget* TBitmapGadgetDesc::ConstructGadget()
{
return new TBitmapGadget(ImageResIdOrIndex, Id, GadgetBorderStyle,
NumImages, StartImage, SharedCels);
}
// ******************** TCommandCategory **************************************
TCommandCategory::TCommandCategory(LPCTSTR name):
Array(5,0,5)
{
PRECONDITION(name);
Name = name;
}
void TCommandCategory::CheckConsistence()
// Delete all duplicate id's in this group
{
uint i,j, num = Array.GetItemsInContainer();
int id, ifound;
for (i=0; i<num; i++) {
id = Array[i];
ifound = 0;
for (j=0; j<num; j++) {
if (Array[j] == id)
ifound++;
if (ifound > 1) {
Array.Destroy(j);
num--;
j--;
ifound--;
TRACEX(GadgetDesc, 1, "TCommandCategory @" << (void*)this <<
" Delete duplicate id: " << id);
}
}
}
}
bool TCommandCategory::operator ==(const TCommandCategory& g) const
{
if (Name == g.Name &&
Array.GetItemsInContainer() == g.Array.GetItemsInContainer()) {
for (uint i=0; i<Array.GetItemsInContainer(); i++) {
if (Array[i] != g.Array[i])
return false;
}
return true;
}
return false;
}
// ******************** TButtonGadgetGruop ************************************
TButtonGadgetGroup::TButtonGadgetGroup(TButtonGadget::TType buttonGadgetType):
Array(5,0,5)
{
CHECK(buttonGadgetType != TButtonGadget::Command);
CHECK(buttonGadgetType != TButtonGadget::NonExclusive);
// Without diagnostic set ButtonGadgetType to Exclusive
//
if (buttonGadgetType == TButtonGadget::Command ||
buttonGadgetType == TButtonGadget::NonExclusive)
ButtonGadgetType = TButtonGadget::Exclusive;
else
ButtonGadgetType = buttonGadgetType;
}
void TButtonGadgetGroup::CheckConsistence()
// Delete all duplicate id's in this group
{
uint i,j, num = Array.GetItemsInContainer();
int id, ifound;
for (i=0; i<num; i++) {
id = Array[i];
ifound = 0;
for (j=0; j<num; j++) {
if (Array[j] == id)
ifound++;
if (ifound > 1) {
Array.Destroy(j);
num--;
j--;
ifound--;
TRACEX(GadgetDesc, 1, "TButtonGadgetGroup @" << (void*)this <<
" Delete duplicate id: " << id);
}
}
}
}
bool TButtonGadgetGroup::operator ==(const TButtonGadgetGroup& g) const
{
if (ButtonGadgetType == g.ButtonGadgetType &&
Array.GetItemsInContainer() == g.Array.GetItemsInContainer()) {
for (uint i=0; i<Array.GetItemsInContainer(); i++) {
if (Array[i] != g.Array[i])
return false;
}
return true;
}
return false;
}
// ******************** TGadgetDescriptors ************************************
TGadgetDescriptors::TGadgetDescriptors():
Array(5,0,5),
Groups(5,0,5),
Categories(5,0,5)
{
Array.Add(new TSeparatorGadgetDesc());
Array.Add(new TInvisibleGadgetDesc());
}
TGadget* TGadgetDescriptors::ConstructGadget(int id)
{
uint i;
for (i=0; i<Array.GetItemsInContainer(); i++)
if (Array[i]->Id == id)
return Array[i]->ConstructGadget();
return 0;
}
TGadgetDesc* TGadgetDescriptors::Find(int id)
{
uint i;
for (i=0; i<Array.GetItemsInContainer(); i++)
if (Array[i]->Id == id)
return Array[i];
return 0;
}
TButtonGadgetGroup* TGadgetDescriptors::FindGroup(int id)
{
uint i,j;
TButtonGadgetDesc* desc = TYPESAFE_DOWNCAST(Find(id), TButtonGadgetDesc);
if (desc) {
for (i=0; i<Groups.GetItemsInContainer(); i++)
for (j=0; j<Groups[i]->Array.GetItemsInContainer(); j++)
if (Groups[i]->Array[j] == id)
return Groups[i];
}
return 0;
}
// return the first category where a gadget with id is found
//
TCommandCategory* TGadgetDescriptors::FindCategory(int id)
{
uint i,j;
TButtonGadgetDesc* desc = TYPESAFE_DOWNCAST(Find(id), TButtonGadgetDesc);
if (desc) {
for (i=0; i<Categories.GetItemsInContainer(); i++)
for (j=0; j<Categories[i]->Array.GetItemsInContainer(); j++)
if (Categories[i]->Array[j] == id)
return Categories[i];
}
return 0;
}
// return the category with name
//
TCommandCategory* TGadgetDescriptors::FindCategory(owl::tstring name)
{
for (uint i=0; i<Categories.GetItemsInContainer(); i++) {
if (Categories[i]->Name == name)
return Categories[i];
}
return 0;
}
void TGadgetDescriptors::CheckConsistence()
// Checks the consistence of all TButtonGadgetDesc and TButtonGadgetGroups
// Should be called after all members are added
{
uint i, j, k, num, num2;
int id, ifound;
TButtonGadgetDesc* buttonDesc;
TButtonGadgetGroup* group;
// If there exist more than one GadgetDesc with the same id,
// delete the second one
//
num = Array.GetItemsInContainer();
for (i=0; i<num; i++) {
id = Array[i]->Id;
ifound = 0;
for (j=0; j<num; j++) {
if (Array[j]->Id == id)
ifound++;
if (ifound > 1) {
Array.Destroy(j);
num--;
j--;
ifound--;
TRACEX(GadgetDesc, 1, "TGadgetDescriptor: Delete duplicate id: " << id);
}
}
}
// Delete duplicate id's in every group
//
num = Groups.GetItemsInContainer();
for (i=0; i<num; i++) {
Groups[i]->CheckConsistence();
}
// Delete duplicate id's in every category
//
num = Categories.GetItemsInContainer();
for (i=0; i<num; i++) {
Categories[i]->CheckConsistence();
}
// If the id of the ButtonGadgetDesc exist more than one
// time in the ButtonGadgetGroups. Delete the id in the second group
//
num = Array.GetItemsInContainer();
for (i=0; i<num; i++) {
buttonDesc = TYPESAFE_DOWNCAST(Array[i], TButtonGadgetDesc);
if (buttonDesc) {
id = Array[i]->Id;
ifound = 0;
for (j=0; j<Groups.GetItemsInContainer(); j++) {
num2 = Groups[j]->Array.GetItemsInContainer();
for (k=0; k<num2; k++) {
if (Groups[j]->Array[k] == id)
ifound ++;
if (ifound > 1) {
Groups[j]->Array.Destroy(k);
ifound--;
k--;
num2--;
TRACEX(GadgetDesc, 1, "TButtonGadgetGroup @" << (void*)Groups[j] <<
" Delete duplicate id: " << id);
}
}
}
}
}
// If the id of the GadgetDesc exist more than one
// time in the CommandCategories. Delete the id in the second category
//
num = Array.GetItemsInContainer();
for (i=0; i<num; i++) {
if (Array[i]) {
id = Array[i]->Id;
ifound = 0;
for (j=0; j<Categories.GetItemsInContainer(); j++) {
num2 = Categories[j]->Array.GetItemsInContainer();
for (k=0; k<num2; k++) {
if (Categories[j]->Array[k] == id)
ifound ++;
if (ifound > 1) {
Categories[j]->Array.Destroy(k);
ifound--;
k--;
num2--;
TRACEX(GadgetDesc, 1, "TCommandCategoy @" << (void*)Categories[j] <<
" Delete duplicate id: " << id);
}
}
}
}
}
// If there exist a id in a group, that has no associated TButtonGadgetDesc
// delete the id in the group
//
num = Groups.GetItemsInContainer();
for (i=0; i<num; i++) {
num2 = Groups[i]->Array.GetItemsInContainer();
for (j=0; j<num2; j++) {
id = Groups[i]->Array[j];
buttonDesc = TYPESAFE_DOWNCAST(Find(id),
TButtonGadgetDesc);
if (buttonDesc == 0) {
Groups[i]->Array.Destroy(j);
j--;
num2--;
TRACEX(GadgetDesc, 1, "TButtonGadgetGroup @" << (void*)Groups[i] <<
" Delete id: " << id <<
" Reason: Is not a button gadget");
}
}
}
// If there exist a id in a category, that is not a command gadget
// delete the id in the category
//
num = Categories.GetItemsInContainer();
for (i=0; i<num; i++) {
num2 = Categories[i]->Array.GetItemsInContainer();
for (j=0; j<num2; j++) {
id = Categories[i]->Array[j];
TGadgetDesc* desc = TYPESAFE_DOWNCAST(Find(id), TGadgetDesc);
if (!(desc && (desc->Attr & GADG_ISCOMMAND))) {
Categories[i]->Array.Destroy(j);
j--;
num2--;
TRACEX(GadgetDesc, 1, "TCommandCategory @" << (void*)Categories[i] <<
" Delete id: " << id <<
" Reason: Is not a command gadget");
}
}
}
// Destroy all groups, that are empty
//
num = Groups.GetItemsInContainer();
for (i=0; i<num; i++) {
if (Groups[i]->Array.GetItemsInContainer() == 0) {
TRACEX(GadgetDesc, 1, "Delete empty TButtonGadgetGroup @" <<
(void*)Groups[i]);
Groups.Destroy(i);
i--;
num--;
}
}
// Destroy all categories, that are empty
//
num = Categories.GetItemsInContainer();
for (i=0; i<num; i++) {
if (Categories[i]->Array.GetItemsInContainer() == 0) {
TRACEX(GadgetDesc, 1, "Delete empty TCommandCategory @" <<
(void*)Categories[i]);
Categories.Destroy(i);
i--;
num--;
}
}
// Checks the consistence of ButtonGadgetType between
// TButtonGadgetDesc and the TButtonGadgetGroup
//
num = Array.GetItemsInContainer();
for (i=0; i<num; i++) {
buttonDesc = TYPESAFE_DOWNCAST(Array[i], TButtonGadgetDesc);
if (buttonDesc) {
id = buttonDesc->Id;
group = FindGroup(id);
if (group) {
if (buttonDesc->ButtonGadgetType != group->ButtonGadgetType) {
buttonDesc->ButtonGadgetType = group->ButtonGadgetType;
}
}
}
}
// If there is a ButtonGadget with Type Exclusive or SemiExclusive and no
// associated group change the Type of ButtonGadget
//
num = Array.GetItemsInContainer();
for (i=0; i<num; i++) {
buttonDesc = TYPESAFE_DOWNCAST(Array[i], TButtonGadgetDesc);
if (buttonDesc && (
buttonDesc->ButtonGadgetType == TButtonGadget::Exclusive ||
buttonDesc->ButtonGadgetType == TButtonGadget::SemiExclusive)) {
id = buttonDesc->Id;
group = FindGroup(id);
if (group == 0) {
// I'm not sure. What is the best error handling for this situation
// I change them to Command if State is Up and to NonExclusive if Down
//
if (buttonDesc->ButtonGadgetState == TButtonGadget::Up)
buttonDesc->ButtonGadgetType = TButtonGadget::Command;
else
buttonDesc->ButtonGadgetType = TButtonGadget::NonExclusive;
}
}
}
num = Groups.GetItemsInContainer();
for (i=0; i<num; i++) {
int iPressed = 0;
if (Groups[i]->ButtonGadgetType != TButtonGadget::Command &&
Groups[i]->ButtonGadgetType != TButtonGadget::NonExclusive) {
// If there is a group with Type Exclusive or SemiExclusive,
// then make sure that only one button is pressed
//
for (j=0; j<Groups[i]->Array.GetItemsInContainer(); j++) {
buttonDesc = TYPESAFE_DOWNCAST(Find(Groups[i]->Array[j]),
TButtonGadgetDesc);
if (buttonDesc->ButtonGadgetState == TButtonGadget::Down)
iPressed++;
if (iPressed > 1) {
buttonDesc->ButtonGadgetState = TButtonGadget::Up;
iPressed--;
}
}
// If there is a Exclusive group and no pressed button,
// then press the first button
//
if (Groups[i]->ButtonGadgetType == TButtonGadget::Exclusive &&
iPressed == 0) {
buttonDesc = TYPESAFE_DOWNCAST(Find(Groups[i]->Array[0]),
TButtonGadgetDesc);
buttonDesc->ButtonGadgetState = TButtonGadget::Down;
}
}
}
}
} // OwlExt namespace
//===============================================================================================
↑ V1004 The 'name' pointer was used unsafely after it was verified against nullptr. Check lines: 376, 377.
↑ V522 There might be dereferencing of a potential null pointer 'buttonDesc'.
↑ V813 Decreased performance. The 'name' argument should probably be rendered as a constant reference.
↑ V818 It is more efficient to use an initialization list 'StartColorSel(startColorSel)' rather than an assignment operator.
↑ V815 Decreased performance. Consider replacing the expression 'Text = ""' with 'Text.clear()'.