/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2024 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#pragma once
#include
#include "guihandler.h"
#include "gdifonts.h"
class BaseInfo {
protected:
void *extra;
GuiHandler *handler;
shared_ptr managedHandler;
bool dataString;
public:
bool matchExtra(int requireExtraMatch) const {
return requireExtraMatch == -1 || requireExtraMatch == getExtraInt();
}
bool hasEventHandler() const {
return handler != 0 || managedHandler;
}
bool handleEvent(gdioutput &gdi, GuiEventType type) {
if (handler) {
handler->handle(gdi, *this, type);
return true;
}
else if (managedHandler) {
managedHandler->handle(gdi, *this, type);
return true;
}
return false;
}
BaseInfo():extra(0), dataString(false), handler(0) {}
virtual ~BaseInfo() {}
string id;
virtual HWND getControlWindow() const = 0;
virtual void refresh() {
InvalidateRect(getControlWindow(), 0, true);
}
BaseInfo &setExtra(const wchar_t *e) {extra=(void *)e; dataString = true; return *this;}
BaseInfo &setExtra(int e) {extra = (void *)size_t(e); return *this;}
BaseInfo &setExtra(size_t e) {extra = (void *)(e); return *this;}
#ifdef _M_X64
BaseInfo &setExtra(unsigned int e) { extra = (void *)size_t(e); return *this; }
#endif
bool isExtraString() const {return dataString;}
wchar_t *getExtra() const {assert(extra == 0 || dataString); return (wchar_t *)extra;}
int getExtraInt() const {return (int)size_t(extra);}
size_t getExtraSize() const {return size_t(extra);}
GuiHandler &getHandler() const;
BaseInfo &setHandler(const GuiHandler *h) {handler = const_cast(h); return *this;}
BaseInfo &setHandler(const shared_ptr &h) { managedHandler = h; return *this; }
void clearHandler() {
handler = nullptr;
managedHandler.reset();
}
};
class GuiEvent final : public BaseInfo {
GUICALLBACK callback = nullptr;
public:
bool makeEvent(gdioutput &gdi, GuiEventType type) {
if (callback)
return callback(&gdi, type, this) != 0;
else
return handleEvent(gdi, type);
return true;
}
GuiEvent(GUICALLBACK callback) : callback(callback) {}
GuiEvent(const shared_ptr &h) {
setHandler(h);
}
GuiEvent(const GuiHandler *h) {
setHandler(h);
}
HWND getControlWindow() const final { throw std::exception("Unsupported"); }
};
class RestoreInfo final : public BaseInfo {
public:
int nLBI;
int nBI;
int nII;
int nTL;
int nRect;
int nHWND;
int nData;
int sCX;
int sCY;
int sMX;
int sMY;
int sOX;
int sOY;
int nTooltip;
int nTables;
shared_ptr onClear;
shared_ptr postClear;
set restorePoints;
bool operator<(const RestoreInfo &r) const {
return nLBI < r.nLBI || nBI < r.nBI || nII < r.nII || nTL < r.nTL || nRect < r.nRect || nData < r.nData;
}
HWND getControlWindow() const final {throw std::exception("Unsupported");}
};
class RectangleInfo final : public BaseInfo {
private:
DWORD color;
DWORD color2;
bool drawBorder;
DWORD borderColor;
RECT rc;
bool border3D;
public:
const RECT &getRect() const {return rc;}
RectangleInfo(): color(0), color2(0), borderColor(0), border3D(false), drawBorder(false) {memset(&rc, 0, sizeof(RECT));}
RectangleInfo &setColor(GDICOLOR c) {color = c; return *this;}
RectangleInfo &setColor2(GDICOLOR c) {color2 = c; return *this;}
RectangleInfo &set3D(bool is3d) {border3D = is3d; return *this;}
RectangleInfo &setBorderColor(GDICOLOR c) {borderColor = c; return *this;}
friend class gdioutput;
friend struct PageInfo;
RectangleInfo &changeDimension(gdioutput &gdi, int dx, int dy);
HWND getControlWindow() const final {throw std::exception("Unsupported");}
};
class TableInfo final: public BaseInfo {
public:
TableInfo():xp(0), yp(0), table(0) {}
int xp;
int yp;
shared_ptr table;
HWND getControlWindow() const final {throw std::exception("Unsupported");}
};
class TextInfo final: public BaseInfo
{
public:
TextInfo():format(0), color(0), xlimit(0), hasTimer(false),
hasCapture(false), callBack(0), highlight(false),
active(false), lineBreakPrioity(0),
absPrintX(0), absPrintY(0), realWidth(0) {
textRect.left = 0; textRect.right = 0;
textRect.top = 0; textRect.bottom = 0;
}
TextInfo &setColor(GDICOLOR c) {color = c; return *this;}
GDICOLOR getColor() const { return GDICOLOR(color); }
TextInfo &changeFont(const wstring &fnt) {font = fnt; return *this;} //Note: size not updated
bool isFormatInfo() const { return format == pageNewPage || format == pagePageInfo || format == pageNewChapter; }
int getHeight() const { return int(textRect.bottom - textRect.top); }
int getWidth() const { return realWidth; }
int getX() const { return xp; }
int getY() const { return yp; }
gdiFonts getGdiFont() const {return gdiFonts(format & 0xFF);}
// Sets absolute print coordinates in [mm]
TextInfo &setAbsPrintPos(int x, int y) {
absPrintX = x; absPrintY = y; return *this;
}
wstring text;
wstring font;
int xp = -1;
int yp = -1;
int format;
DWORD color;
int xlimit;
int lineBreakPrioity;
int absPrintX;
int absPrintY;
bool hasTimer;
DWORD zeroTime = -1;
DWORD timeOut = 0;
bool hasCapture;
GUICALLBACK callBack;
RECT textRect;
int realWidth; // The calculated actual width of the string in pixels
bool highlight;
bool active;
HWND getControlWindow() const final {throw std::exception("Unsupported");}
friend class gdioutput;
};
class ButtonInfo final : public BaseInfo {
private:
bool originalState;
bool isEditControl;
bool checked;
bool* updateLastData;
void synchData() const { if (updateLastData) *updateLastData = checked; }
public:
ButtonInfo() : callBack(0), hWnd(0), AbsPos(false), fixedRightTop(false),
flags(0), storedFlags(0), originalState(false), isEditControl(false),
isCheckbox(false), checked(false), updateLastData(0) {}
ButtonInfo& isEdit(bool e) { isEditControl = e; return *this; }
int xp;
int yp;
int width;
wstring text;
HWND hWnd;
bool AbsPos;
bool fixedRightTop;
int flags;
int storedFlags;
bool isCheckbox;
bool isDefaultButton() const { return (flags & 1) == 1; }
bool isCancelButton() const { return (flags & 2) == 2; }
ButtonInfo& setSynchData(bool* variable) { updateLastData = variable; return *this; }
int getX() const { return xp; }
int getY() const { return yp; }
void moveButton(gdioutput& gdi, int xp, int yp);
void getDimension(const gdioutput& gdi, int& w, int& h) const;
ButtonInfo& setDefault();
ButtonInfo& setCancel() { flags |= 2, storedFlags |= 2; return *this; }
ButtonInfo& fixedCorner() { fixedRightTop = true; return *this; }
GUICALLBACK callBack;
friend class gdioutput;
HWND getControlWindow() const final { return hWnd; }
};
enum gdiFonts;
class InputInfo final: public BaseInfo {
public:
InputInfo();
wstring text;
bool changed() const {return text!=original;}
void ignore(bool ig) {ignoreCheck=ig;}
InputInfo &isEdit(bool e) {isEditControl=e; return *this;}
InputInfo &setBgColor(GDICOLOR c) {bgColor = c; return *this;}
InputInfo &setFgColor(GDICOLOR c) {fgColor = c; return *this;}
InputInfo &setFont(gdioutput &gdi, gdiFonts font);
GDICOLOR getBgColor() const {return bgColor;}
GDICOLOR getFgColor() const {return fgColor;}
/** Return the previously stored text */
const wstring &getPreviousText() const { return focusText; }
bool changedInput() const { return text != focusText; }
InputInfo &setPassword(bool pwd);
HWND getControlWindow() const final {return hWnd;}
InputInfo &setSynchData(wstring *variable) {updateLastData = variable; return *this;}
int getX() const {return xp;}
int getY() const {return yp;}
int getWidth() const {return int(width);}
int getHeight() const { return int(height); }
private:
HWND hWnd;
GUICALLBACK callBack;
void synchData() const {if (updateLastData) *updateLastData = text;}
wstring *updateLastData;
int xp;
int yp;
double width;
double height;
GDICOLOR bgColor;
GDICOLOR fgColor;
bool isEditControl;
bool writeLock;
wstring original;
wstring focusText; // Text when got focus
bool ignoreCheck; // True if changed-state should be ignored
friend class gdioutput;
};
class ListBoxInfo final : public BaseInfo {
public:
ListBoxInfo() : hWnd(0), callBack(0), IsCombo(false), index(-1),
writeLock(false), ignoreCheck(false), isEditControl(true),
originalProc(0), lbiSync(0), multipleSelection(false),
xp(0), yp(0), width(0), height(0), data(0), lastTabStop(0),
updateLastData(0) {}
wstring text;
size_t data;
int getDataInt() const { return (int)data; }
int index;
bool changed() const { return text != original; }
void ignore(bool ig) { ignoreCheck = ig; }
ListBoxInfo& isEdit(bool e) { isEditControl = e; return *this; }
HWND getControlWindow() const final { return hWnd; }
void copyUserData(ListBoxInfo& userLBI) const;
ListBoxInfo& setSynchData(int* variable) { updateLastData = variable; return *this; }
int getWidth() const { return int(width); }
int getHeight() const { return int(height); }
int getX() const { return xp; }
int getY() const { return yp; }
bool isCombo() const { return IsCombo; }
private:
void syncData() const { if (updateLastData) *updateLastData = data; }
bool IsCombo;
int* updateLastData;
GUICALLBACK callBack;
int xp;
int yp;
double width;
double height;
HWND hWnd;
int lastTabStop;
bool multipleSelection;
bool isEditControl;
bool writeLock;
wstring original;
size_t originalIdx;
bool ignoreCheck; // True if changed-state should be ignored
unordered_map data2Index;
uint64_t computed_hash = 0;
static uint64_t computeItemHash(const vector>& items);
// Synchronize with other list box
WNDPROC originalProc;
ListBoxInfo* lbiSync;
friend LRESULT CALLBACK GetMsgProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
friend class gdioutput;
};
class DataStore {
public:
DataStore() {
data = 0;
}
string id;
void *data;
string sdata;
};
class EventInfo final: public BaseInfo {
private:
string origin;
DWORD data;
KeyCommandCode keyEvent;
public:
KeyCommandCode getKeyCommand() const {return keyEvent;}
DWORD getData() const {return data;}
void setKeyCommand(KeyCommandCode kc) {keyEvent = kc;}
void setData(const string &origin_, DWORD d) {origin = origin_, data = d;}
const string &getOrigin() {return origin;}
EventInfo();
GUICALLBACK callBack;
HWND getControlWindow() const final {throw std::exception("Unsupported");}
};
class TimerInfo final : public BaseInfo {
private:
static int globalTimerId;
int timerId;
DWORD dataInt;
wstring dataString;
gdioutput* parent;
HWND setWnd;
public:
~TimerInfo();
TimerInfo(gdioutput* gdi, GUICALLBACK cb) : parent(gdi), callBack(cb), setWnd(0), timerId(++globalTimerId) {}
TimerInfo(const TimerInfo&) = delete;
TimerInfo& operator=(const TimerInfo&) = delete;
int getId() const { return timerId; }
BaseInfo& setExtra(const wchar_t* e) { return BaseInfo::setExtra(e); }
BaseInfo& setExtra(int e) { return BaseInfo::setExtra(e); }
void setData(DWORD d, const wstring& s) { dataInt = d; dataString = s; }
const wstring& getDataString() {
return dataString;
}
DWORD getData() {
return dataInt;
}
GUICALLBACK callBack;
friend class gdioutput;
friend void CALLBACK gdiTimerProc(HWND hWnd, UINT a, UINT_PTR ptr, DWORD b);
HWND getControlWindow() const final { throw std::exception("Unsupported"); }
};
class InfoBox final: public BaseInfo {
public:
InfoBox() : callBack(0), HasCapture(0), HasTCapture(0), TimeOut(0) {}
wstring text;
GUICALLBACK callBack;
RECT TextRect;
RECT Close;
RECT BoundingBox;
bool HasCapture;
bool HasTCapture;
DWORD TimeOut;
HWND getControlWindow() const final {throw std::exception("Unsupported");}
};
typedef list TIList;
struct ToolInfo {
string name;
TOOLINFOW ti;
wstring tip;
uintptr_t id;
};