cmake-d/samples/minwin_gtk/minwin/button.d
2007-08-28 16:16:58 +00:00

376 lines
13 KiB
D

/* MinWin Button classes
*
* Various button classes like PushButtons
*
* Written by Ben Hinkle and released to the public domain, as
* explained at http://creativecommons.org/licenses/publicdomain
* Report comments and bugs at dsource: http://www.dsource.org/projects/minwin
*/
module minwin.button;
public import minwin.component;
private {
import minwin.icon;
import minwin.app;
import minwin.window;
import minwin.peerimpl;
import minwin.logging;
import std.string;
import minwin.peer;
}
abstract class AbstractButton : WindowChild {
int cmd;
Icon icon();
void icon(Icon c);
char[] text();
void text(char[] c);
MultiDelegate!(Component) actionDelegate;
void doCommand(int cmd) {
// only command is action command
version(LOG) log.writefln("calling action delegate");
if (cmd == ButtonClickedCommand) {
actionDelegate(cast(Component)this);
if (this.cmd != 0) {
super.doCommand(this.cmd);
}
}
}
}
abstract class AbstractToggleButton : AbstractButton {
bool selected();
void selected(bool x);
}
version (MinWin32) {
version = SimpleToggleGroup;
}
version (SimpleToggleGroup) {
private import minwin.dialog;
// manages selected state between several ToggleButtons
class ToggleGroup {
AbstractToggleButton[] buttons;
void addButton(AbstractToggleButton[] btns ...) {
buttons ~= btns;
foreach(b; btns) {
b.actionDelegate ~= &select;
}
}
void select(Component c) {
version (LOG) log.writefln("selecting component ", c);
foreach(AbstractToggleButton b; buttons) {
b.selected = (b is c);
}
}
void select(int index) {
foreach(int n, AbstractToggleButton b; buttons) {
b.selected = n == index;
}
}
int selected() {
foreach(int n, AbstractToggleButton b; buttons) {
version(LOG)log.printf("testing button %d %x\n",n,b);
if (b && b.selected)
return n;
}
version(LOG)log.printf(" no button selected??\n");
return 0;
}
}
}
version (MinWin32) {
private import minwin.mswindows;
const int ButtonClickedCommand = BN_CLICKED;
template PreferredSizeImpl() {
const int paddingX;
const int paddingY;
Point preferredSize() {
int width,height;
HDC dc = GetDC(peer);
sysAssert(dc !is null, "Failed to get button DC in preferredSize");
SIZE s;
try {
Font f = standardFont(StandardFont.Gui);
HFONT oldfont = SelectObject(dc,f.peer);
sysAssert(oldfont !is null, "Failed to get Button font in preferredSize");
BOOL status = GetTextExtentPoint32X(dc,text_data,text_data.length,&s);
SelectObject(dc,oldfont);
sysAssert(status != false, "Failed to get font extents in preferredSize");
} finally {
ReleaseDC(peer,dc);
}
width = s.cx > 75-paddingX ? s.cx+paddingX*2 : 75;
height = s.cy > 23-paddingY ? s.cy+paddingY*2 : 23;
if (userPreferredWidth_data > 0)
width = userPreferredWidth_data;
if (userPreferredHeight_data > 0)
height = userPreferredHeight_data;
return XY(width,height);
// Requires WinXP
// SIZE sz;
// SendMessageA(peer,BCM_GETIDEALSIZE,0,cast(int)&sz);
// width = sz.cx;
// height = sz.cy;
}
}
template SelectedImpl() {
bool selected() {
version(LOG)log.printf("sending message...");
bool res = SendMessageA(peer,BM_GETCHECK,0,0) == BST_CHECKED;
version(LOG)log.printf(" got %d\n",res);
return res;
}
void selected(bool x) {
SendMessageA(peer,BM_SETCHECK,x,0);
}
}
template IconTextImpl() {
Icon icon_data;
Icon icon() { return icon_data; }
void icon(Icon c) {
icon_data = c;
SendMessageA(peer,BM_SETIMAGE,cast(WPARAM)c.peer,0);
}
char[] text_data;
char[] text() { return text_data; }
void text(char[] c) {
text_data = c;
SendMessageX(peer,WM_SETTEXT,0,c);
}
}
class Button : AbstractButton {
this(Component parent, char[] intext, char[] name = "") {
paddingX = GetSystemMetrics(SM_CXFIXEDFRAME)*2;
paddingY = GetSystemMetrics(SM_CXFIXEDFRAME)*2;
PeerForAdd parentp = parent.getPeerForAdd();
text_data = intext;
peer = CreateWindowX("BUTTON",intext,
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
0,0,10,10,parentp,
cast(HMENU)0,gApp.hInstance,null);
sysAssert(peer !is null, "Failed to create peer Button");
finish_button_setup(this,parent,name,peer);
}
mixin WindowChildImpl!();
mixin IconTextImpl!();
mixin PreferredSizeImpl!();
}
class CheckBox : AbstractToggleButton {
this(Component parent, char[] intext, char[] name = "") {
paddingX = GetSystemMetrics(SM_CXMENUCHECK);
paddingY = GetSystemMetrics(SM_CYFIXEDFRAME)*2;
PeerForAdd parentp = parent.getPeerForAdd();
text_data = intext;
peer = CreateWindowX("BUTTON",intext,
BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE,
0,0,10,10,parentp,
cast(HMENU)0,gApp.hInstance,null);
sysAssert(peer !is null, "Failed to create peer CheckBox");
finish_button_setup(this,parent,name,peer);
}
mixin WindowChildImpl!();
mixin SelectedImpl!();
mixin IconTextImpl!();
mixin PreferredSizeImpl!();
}
class RadioButton : AbstractToggleButton {
this(Component parent, char[] intext, char[] name = "") {
paddingX = GetSystemMetrics(SM_CXMENUCHECK);
paddingY = GetSystemMetrics(SM_CYFIXEDFRAME)*2;
PeerForAdd parentp = parent.getPeerForAdd();
text_data = intext;
peer = CreateWindowX("BUTTON",intext,
BS_RADIOBUTTON | WS_CHILD | WS_VISIBLE,
0,0,10,10,parentp,
cast(HMENU)0,gApp.hInstance,null);
sysAssert(peer !is null, "Failed to create peer RadioButton");
finish_button_setup(this,parent,name,peer);
}
mixin WindowChildImpl!();
mixin SelectedImpl!();
mixin IconTextImpl!();
mixin PreferredSizeImpl!();
}
class ToggleButton : AbstractToggleButton {
this(Component parent, char[] intext, char[] name = "") {
paddingX = GetSystemMetrics(SM_CXFIXEDFRAME)*2;
paddingY = GetSystemMetrics(SM_CYFIXEDFRAME)*2;
PeerForAdd parentp = parent.getPeerForAdd();
text_data = intext;
peer = CreateWindowX("BUTTON",intext,
BS_PUSHLIKE | BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE,
0,0,10,10,parentp,
cast(HMENU)0,gApp.hInstance,null);
sysAssert(peer !is null, "Failed to create peer ToggleButton");
finish_button_setup(this,parent,name,peer);
}
mixin WindowChildImpl!();
mixin SelectedImpl!();
mixin IconTextImpl!();
mixin PreferredSizeImpl!();
}
private void finish_button_setup(AbstractButton b,Component parent,
char[] name, WindowChildPeer peer) {
setWindowChildPeer(b,peer,OWNS_PEER);
b.name = name;
Font f = standardFont(StandardFont.Gui);
SendMessageA(peer,WM_SETFONT,cast(WPARAM)f.peer,0);
parent.addChild(b);
}
} else version (GTK) {
private import minwin.gtk;
private import std.c.string;
const int ButtonClickedCommand = 1;
abstract class HeavyAbstractToggleButton : AbstractToggleButton {
mixin WindowChildImpl!();
}
// manages selected state between several ToggleButtons
class ToggleGroup {
HeavyAbstractToggleButton[] buttons;
void addButton(HeavyAbstractToggleButton[] btns ...) {
buttons ~= btns;
foreach(b; btns) {
RadioButton rb = cast(RadioButton)b;
if (rb is null) {
b.actionDelegate ~= &select;
} else {
// set the RadioButton group to its sibling, if any
if (buttons.length != 0) {
GtkRadioButton* rbpeer1 = cast(GtkRadioButton*)buttons[0].peer;
GtkRadioButton* rbpeer = cast(GtkRadioButton*)rb.peer;
GSList* group = gtk_radio_button_get_group(rbpeer1);
gtk_radio_button_set_group(rbpeer,group);
}
}
}
}
void select(Component c) {
version (LOG) log.writefln("selecting component ", c);
foreach(HeavyAbstractToggleButton b; buttons) {
b.selected = (b is c);
}
}
void select(int index) {
foreach(int n, HeavyAbstractToggleButton b; buttons) {
b.selected = n == index;
}
}
int selected() {
foreach(int n, HeavyAbstractToggleButton b; buttons) {
if (b.selected)
return n;
}
}
}
template SelectedImpl() {
bool selected() {
return gtk_toggle_button_get_active(cast(GtkToggleButton*)peer) != 0;
}
void selected(bool x) {
gtk_toggle_button_set_active(cast(GtkToggleButton*)peer,x);
}
}
template IconTextImpl() {
Icon icon_data;
Icon icon() { return icon_data; }
void icon(Icon c) {
icon_data = c;
// SendMessageA(peer,BM_SETIMAGE,cast(WPARAM)c.peer,0);
}
char[] text() {
char* str = gtk_button_get_label(cast(GtkButton*)peer);
if (str is null)
return "";
else
return str[0..strlen(str)].dup;
}
void text(char[] c) {
gtk_button_set_label(cast(GtkButton*)peer,toStringz(c));
}
}
class Button : AbstractButton {
this(Component parent, char[] text, char[] name = "") {
PeerForAdd parentp = parent.getPeerForAdd();
this.name = name;
char* str = toStringz(text);
peer = gtk_button_new_with_label(str);
finish_button_setup(this,peer,parentp,parent);
}
mixin WindowChildImpl!();
mixin IconTextImpl!();
}
class CheckBox : HeavyAbstractToggleButton {
this(Component parent, char[] text, char[] name = "") {
PeerForAdd parentp = parent.getPeerForAdd();
this.name = name;
char* str = toStringz(text);
peer = gtk_check_button_new_with_label(str);
finish_button_setup(this,peer,parentp,parent);
}
mixin SelectedImpl!();
mixin IconTextImpl!();
}
class RadioButton : HeavyAbstractToggleButton {
this(Component parent, char[] text, char[] name = "") {
PeerForAdd parentp = parent.getPeerForAdd();
this.name = name;
char* str = toStringz(text);
peer = gtk_radio_button_new_with_label(null,str);
finish_button_setup(this,peer,parentp,parent);
}
mixin SelectedImpl!();
mixin IconTextImpl!();
}
class ToggleButton : HeavyAbstractToggleButton {
this(Component parent, char[] text, char[] name = "") {
PeerForAdd parentp = parent.getPeerForAdd();
this.name = name;
char* str = toStringz(text);
peer = gtk_toggle_button_new_with_label(str);
finish_button_setup(this,peer,parentp,parent);
}
mixin SelectedImpl!();
mixin IconTextImpl!();
}
private void finish_button_setup(AbstractButton b,
WindowChildPeer peer,
PeerForAdd parentp,
Component parent) {
gtk_widget_set_sensitive(peer,true);
gtk_container_add(cast(GtkContainer*)parentp,peer);
g_signal_connect_data(peer,"clicked",
cast(GCallback)&mw_buttonclick_callback,
cast(gpointer)b,
null,cast(GConnectFlags)0);
setWindowChildPeer(b,peer,OWNS_PEER);
parent.addChild(b);
gtk_widget_realize(peer);
b.visible = true;
}
extern (C) void mw_buttonclick_callback(GtkButton *but, gpointer ud) {
Component c = cast(Component) ud;
if (c) {
c.doCommand(ButtonClickedCommand);
}
}
}