mirror of https://github.com/deavminet/gustav.git
Compare commits
139 Commits
Author | SHA1 | Date |
---|---|---|
Tristan B. Kildaire | 426a65cf96 | |
Tristan B. Kildaire | 66bb86e4cd | |
Tristan B. Kildaire | 3d6e01fb2a | |
Tristan B. Kildaire | a14d67e0fd | |
Tristan B. Kildaire | e0bd021db1 | |
Tristan B. Kildaire | f2120f5fd4 | |
Tristan B. Kildaire | ddee77a5b7 | |
Tristan B. Kildaire | 75ac2e16d4 | |
Tristan B. Kildaire | 5bac2157f8 | |
Tristan B. Kildaire | 302603a6f6 | |
Tristan B. Kildaire | 40342772c2 | |
Tristan B. Kildaire | 13d5176a89 | |
Tristan B. Kildaire | e6ef053f13 | |
Tristan B. Kildaire | 602d23e067 | |
Tristan B. Kildaire | 37c1afeaaa | |
Tristan B. Kildaire | 21f60747a6 | |
Tristan B. Kildaire | 4c687b06eb | |
Tristan B. Kildaire | e75aee2221 | |
Tristan B. Kildaire | 4ff60a02c9 | |
Tristan B. Kildaire | a3d70929e5 | |
Tristan B. Kildaire | 029cd5a3ee | |
Tristan B. Kildaire | be543d33fd | |
Tristan B. Kildaire | a9b3617b0d | |
Tristan B. Kildaire | 31611d6f94 | |
Tristan B. Kildaire | d4912089b1 | |
Tristan B. Kildaire | 638b1bfa9b | |
Tristan B. Kildaire | 58951da6b0 | |
Tristan B. Kildaire | 1420e8e86f | |
Tristan B. Kildaire | 27c42711e0 | |
Tristan B. Kildaire | f5791f2eae | |
Tristan B. Kildaire | 97295cf042 | |
Tristan B. Kildaire | ce9a675da0 | |
Tristan B. Kildaire | 62895ccaee | |
Tristan B. Kildaire | ecd23539ab | |
Tristan B. Kildaire | 5ea0a76a08 | |
Tristan B. Kildaire | e965b9a82c | |
Tristan B. Kildaire | 68ad0e5f38 | |
Tristan B. Kildaire | 01578ab03b | |
Tristan B. Kildaire | 95f36698f7 | |
Tristan B. Kildaire | d10c8f1c3c | |
Tristan B. Kildaire | 624d53d909 | |
Tristan B. Kildaire | 1da36e6936 | |
Tristan B. Kildaire | 015521082e | |
Tristan B. Kildaire | 27bc84da56 | |
Tristan B. Kildaire | 9bc6deb17d | |
Tristan B. Kildaire | 4894017ad5 | |
Tristan B. Kildaire | 347221d1a2 | |
Tristan B. Kildaire | 185e5efd5f | |
Tristan B. Kildaire | 32deadfc83 | |
Tristan B. Kildaire | ac48d440bd | |
Tristan B. Kildaire | b090584fbd | |
Tristan B. Kildaire | 87db85f7aa | |
Tristan B. Kildaire | 3ee0830b65 | |
Tristan B. Kildaire | 0a3b4acb14 | |
Tristan B. Kildaire | 7c60695cce | |
Tristan B. Kildaire | f83ff298bd | |
Tristan B. Kildaire | 5d1e9c2454 | |
Tristan B. Kildaire | b0ace4deeb | |
Tristan B. Kildaire | 8d5be66f2b | |
Tristan B. Kildaire | 6ca88b2717 | |
Tristan B. Kildaire | cac85f254e | |
Tristan B. Kildaire | c347490291 | |
Tristan B. Kildaire | 9561e1cbb7 | |
Tristan B. Kildaire | e49824b58b | |
Tristan B. Kildaire | 29fba2f7bd | |
Tristan B. Kildaire | e0293bfe7b | |
Tristan B. Kildaire | f57758777e | |
Tristan B. Kildaire | 3b22f095bb | |
Tristan B. Kildaire | 77575c6ff1 | |
Tristan B. Kildaire | 0f6aabb311 | |
Tristan B. Kildaire | 912fdb3745 | |
Tristan B. Kildaire | 2454a4b484 | |
Tristan B. Kildaire | 7d0542086d | |
Tristan B. Kildaire | d086492730 | |
Tristan B. Kildaire | 5ddc84417d | |
Tristan B. Kildaire | 8060ff34d6 | |
Tristan B. Kildaire | eb9c72d0e1 | |
Tristan B. Kildaire | c4d149782f | |
Tristan B. Kildaire | 0e40518dc4 | |
Tristan B. Kildaire | 0c2fd122f3 | |
Tristan B. Kildaire | 2c3040391d | |
Tristan B. Kildaire | b6781a4ce0 | |
Tristan B. Kildaire | 0c3479eac6 | |
Tristan B. Kildaire | 682c5e482e | |
Tristan B. Kildaire | 9ea68ca748 | |
Tristan B. Kildaire | c9ee505167 | |
Tristan B. Kildaire | 001860b875 | |
Tristan B. Kildaire | 953493cb07 | |
Tristan B. Kildaire | bf36f033be | |
Tristan B. Kildaire | ed909a0558 | |
Tristan B. Kildaire | 5ae50a098f | |
Tristan B. Kildaire | 4bab9d04c5 | |
Tristan B. Kildaire | 413502d1ee | |
Tristan B. Kildaire | ef2a48c684 | |
Tristan B. Kildaire | 7ec56f1036 | |
Tristan B. Kildaire | 4d2ff21cc8 | |
Tristan B. Kildaire | f51a118348 | |
Tristan B. Kildaire | 26685a322c | |
Tristan B. Kildaire | 700ccfa3c0 | |
Tristan B. Kildaire | 65eb2d2518 | |
Tristan B. Kildaire | 168a7c7e12 | |
Tristan B. Kildaire | 63e0b09751 | |
Tristan B. Kildaire | 9f1d51bbba | |
Tristan B. Kildaire | 0e30d54fe6 | |
Tristan B. Kildaire | ec150159df | |
Tristan B. Kildaire | 8546dff6e6 | |
Tristan B. Kildaire | 7da8efee61 | |
Tristan B. Kildaire | 5332d26be9 | |
Tristan B. Kildaire | 99f22f96e3 | |
Tristan B. Kildaire | c0e55329df | |
Tristan B. Kildaire | de38f78432 | |
Tristan B. Kildaire | 00482eeccc | |
Tristan B. Kildaire | 7f8ae349fe | |
Tristan B. Kildaire | a52dbc744e | |
Tristan B. Kildaire | c973463cd7 | |
Tristan B. Kildaire | 4437bf4fce | |
Tristan B. Kildaire | f612d9c727 | |
Tristan B. Kildaire | 3e5db759e5 | |
Tristan B. Kildaire | 301c09c063 | |
Tristan B. Kildaire | 29556a6d8c | |
Tristan B. Kildaire | 7ae11e120e | |
Tristan B. Kildaire | ac9ea39a8f | |
Tristan B. Kildaire | 730c5348f1 | |
Tristan B. Kildaire | 4ab6ef6040 | |
Tristan B. Kildaire | 5ab62e5c4a | |
Tristan B. Kildaire | 860fa3b714 | |
Tristan B. Kildaire | 4b691eeab3 | |
Tristan B. Kildaire | 65720725c3 | |
Tristan B. Kildaire | 1f146e9d4a | |
Tristan B. Kildaire | 58b002afa5 | |
Tristan B. Kildaire | 0bffe2fb27 | |
Tristan B. Kildaire | 72cf00a614 | |
Tristan B. Kildaire | 409f25250d | |
Tristan B. Kildaire | 4587e41aee | |
Tristan B. Kildaire | ad85be4f55 | |
Tristan B. Kildaire | 5bfe749f72 | |
Tristan B. Kildaire | dd043623ef | |
Tristan B. Kildaire | a6bcf811f1 | |
Tristan B. Kildaire | 29b1bc84c7 |
|
@ -23,3 +23,4 @@ docs/
|
|||
# Code coverage
|
||||
*.lst
|
||||
unnamed-thing
|
||||
gustav
|
||||
|
|
5
dub.json
5
dub.json
|
@ -4,8 +4,9 @@
|
|||
],
|
||||
"copyright": "Copyright © 2020, Tristan B. Kildaire",
|
||||
"dependencies": {
|
||||
"gtk-d": "~>3.9.0",
|
||||
"libdnet": "~>0.1.5"
|
||||
"gogga": "0.0.2",
|
||||
"gtk-d": "3.9.0",
|
||||
"libdnet": "0.2.3"
|
||||
},
|
||||
"description": "GTK graphical DNET client",
|
||||
"license": "GPL v3",
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
"fileVersion": 1,
|
||||
"versions": {
|
||||
"bformat": "1.0.8",
|
||||
"gogga": "0.0.2",
|
||||
"gtk-d": "3.9.0",
|
||||
"libdnet": "0.1.5",
|
||||
"libdnet": "0.2.3",
|
||||
"tristanable": "0.1.1"
|
||||
}
|
||||
}
|
||||
|
|
187
source/Channel.d
187
source/Channel.d
|
@ -1,187 +0,0 @@
|
|||
/**
|
||||
* Channel
|
||||
*
|
||||
* Represents a channel which is a collection
|
||||
* of the channel name the users list widget,
|
||||
* the title widget and the chat list box widget
|
||||
* along with the input box state
|
||||
*/
|
||||
|
||||
import gtk.Box;
|
||||
import gtk.ListBox;
|
||||
import gtk.Label;
|
||||
import gtk.TextView;
|
||||
import libdnet.dclient;
|
||||
import gtk.Label;
|
||||
import std.string;
|
||||
import gtk.Button;
|
||||
|
||||
public final class Channel
|
||||
{
|
||||
private DClient client;
|
||||
|
||||
/**
|
||||
* Channel details
|
||||
*/
|
||||
private string channelName;
|
||||
|
||||
/**
|
||||
* The container for this Channel
|
||||
*/
|
||||
private Box box;
|
||||
|
||||
/**
|
||||
* UI components
|
||||
*
|
||||
* Users's box
|
||||
* - Label users
|
||||
* - ListBox users
|
||||
*/
|
||||
private ListBox users;
|
||||
private ListBox textArea;
|
||||
private TextView textInput;
|
||||
|
||||
/* TODO: No mutexes should be needed (same precaution) as the GTK lock provides safety */
|
||||
private string[] usersString;
|
||||
|
||||
this(DClient client, string channelName)
|
||||
{
|
||||
this.client = client;
|
||||
this.channelName = channelName;
|
||||
|
||||
initializeBox();
|
||||
}
|
||||
|
||||
private void initializeBox()
|
||||
{
|
||||
box = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
/* The user's box */
|
||||
Box userBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* The user's list */
|
||||
users = new ListBox();
|
||||
|
||||
userBox.add(new Label("Users"));
|
||||
|
||||
// import gtk.Expander;
|
||||
// Expander g = new Expander("Bruh");
|
||||
// g.setExpanded(true)
|
||||
// g.add(users);
|
||||
userBox.add(users);
|
||||
|
||||
/* The text box */
|
||||
Box textBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
textBox.add(new Label(channelName));
|
||||
textArea = new ListBox();
|
||||
import gtk.ScrolledWindow;
|
||||
|
||||
ScrolledWindow scrollTextChats = new ScrolledWindow(textArea);
|
||||
textBox.add(scrollTextChats);
|
||||
|
||||
textInput = new TextView();
|
||||
Box textInputBox = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
textInputBox.packStart(textInput,1,1,0);
|
||||
import gtk.Button;
|
||||
|
||||
/* The send button */
|
||||
Button sendButton = new Button("Send");
|
||||
sendButton.addOnClicked(&sendMessageBtn);
|
||||
textInputBox.add(sendButton);
|
||||
textBox.add(textInputBox);
|
||||
|
||||
|
||||
// import gtk.TextView;
|
||||
// TextView f = new TextView();
|
||||
// textBox.add(f);
|
||||
|
||||
|
||||
|
||||
|
||||
box.add(textBox);
|
||||
box.packEnd(userBox,0,0,0);
|
||||
|
||||
textBox.setChildPacking(scrollTextChats, true, true, 0, GtkPackType.START);
|
||||
box.setChildPacking(textBox, true, true, 0, GtkPackType.START);
|
||||
|
||||
}
|
||||
|
||||
private void sendMessageBtn(Button)
|
||||
{
|
||||
client.sendMessage(0, channelName, textInput.getBuffer().getText());
|
||||
}
|
||||
|
||||
public Box getBox()
|
||||
{
|
||||
return box;
|
||||
}
|
||||
|
||||
public string getName()
|
||||
{
|
||||
return channelName;
|
||||
}
|
||||
|
||||
public void populateUsersList()
|
||||
{
|
||||
string[] memberList = client.getMembers(channelName);
|
||||
|
||||
foreach(string member; memberList)
|
||||
{
|
||||
users.add(new Label(member));
|
||||
usersString~=member;
|
||||
}
|
||||
}
|
||||
|
||||
public void channelJoin(string username)
|
||||
{
|
||||
/* Add join message to message log */
|
||||
textArea.add(new Label("--> "~username~" joined the channel"));
|
||||
|
||||
/* Add user to user list */
|
||||
users.add(new Label(username));
|
||||
|
||||
usersString~=username;
|
||||
}
|
||||
|
||||
|
||||
public void channelLeave(string username)
|
||||
{
|
||||
/* Add leave message to message log */
|
||||
textArea.add(new Label("<-- "~username~" left the channel"));
|
||||
|
||||
/* TODO: Better way with just removing one dude */
|
||||
|
||||
/* Remove the user form users list */
|
||||
string[] newUsers;
|
||||
|
||||
foreach(string currentUser; usersString)
|
||||
{
|
||||
if(cmp(currentUser, username))
|
||||
{
|
||||
newUsers ~= currentUser;
|
||||
}
|
||||
}
|
||||
|
||||
usersString = newUsers;
|
||||
|
||||
/* Clear list */
|
||||
users.removeAll();
|
||||
|
||||
foreach(string currentUser; usersString)
|
||||
{
|
||||
users.add(new Label(currentUser));
|
||||
}
|
||||
|
||||
/* Remove user from user list */
|
||||
/* TODO: Do this better */
|
||||
// foreach(Label label; users.get)
|
||||
// users.add(new Label(username));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addMessage(string s)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -5,29 +5,36 @@ import gui;
|
|||
import gdk.Threads : te = threadsEnter, tl = threadsLeave;
|
||||
import gtk.Box;
|
||||
import std.stdio;
|
||||
import libdnet.dclient;
|
||||
import libdnet.client;
|
||||
import std.socket;
|
||||
import gtk.ListBox;
|
||||
import gtk.Label;
|
||||
|
||||
import Channel;
|
||||
import areas.Channel;
|
||||
import areas.MessageArea;
|
||||
import areas.User;
|
||||
import std.string;
|
||||
|
||||
import core.sync.mutex;
|
||||
|
||||
import gtk.Notebook;
|
||||
|
||||
import std.conv;
|
||||
|
||||
import gogga;
|
||||
|
||||
|
||||
|
||||
public final class Connection : Thread
|
||||
{
|
||||
private GUI gui;
|
||||
private Box box;
|
||||
private ListBox channels;
|
||||
private ListBox users;
|
||||
private ListBox textArea;
|
||||
|
||||
private DClient client;
|
||||
private Address address;
|
||||
private string[] auth;
|
||||
private string statusText;
|
||||
|
||||
/* TODO: Check if we need to protect */
|
||||
/* TODO: So far usage is in signal handlers (mutex safved) and within te-tl lock for notifications */
|
||||
|
@ -38,9 +45,18 @@ public final class Connection : Thread
|
|||
* All joined Channel-s in this Connection
|
||||
*/
|
||||
private Notebook notebookSwitcher;
|
||||
private Channel[] chans; /*TODO: Technically locking by GTK would make this not needed */
|
||||
private MessageArea[] areas; /*TODO: Technically locking by GTK would make this not needed */
|
||||
private Mutex chansLock;
|
||||
private Channel focusedChan;
|
||||
private MessageArea focusedArea;
|
||||
|
||||
|
||||
// public void setPrescence(string pres)
|
||||
// {
|
||||
// /* The new status */
|
||||
// string newStatus =
|
||||
// statusText = "";
|
||||
// statusText =
|
||||
// }
|
||||
|
||||
this(GUI gui, Address address, string[] auth)
|
||||
{
|
||||
|
@ -52,6 +68,8 @@ public final class Connection : Thread
|
|||
/* Initialize locks */
|
||||
initializeLocks();
|
||||
|
||||
statusText = "Hey there, I'm using Dnet!";
|
||||
|
||||
/* Start the notification atcher */
|
||||
start();
|
||||
}
|
||||
|
@ -75,6 +93,7 @@ public final class Connection : Thread
|
|||
te();
|
||||
box = getChatPane();
|
||||
gui.notebook.add(box);
|
||||
//gui.notebook.setTabReorderable(box, true);
|
||||
//gui.notebook setChildPacking(box, true, true, 0, GtkPackType.START);
|
||||
// gui.mainWindow.
|
||||
gui.notebook.setTabLabelText(box, auth[0]~"@"~address.toString());
|
||||
|
@ -88,8 +107,15 @@ public final class Connection : Thread
|
|||
client = new DClient(address);
|
||||
client.auth(auth[0], auth[1]); /* TODO: DO this without auth (the list in the loop, crahses server) */
|
||||
|
||||
/* Display all channels */
|
||||
channelList();
|
||||
/* Set your prescense */
|
||||
client.setProperty("pres","available");
|
||||
|
||||
|
||||
|
||||
// te();
|
||||
// import ProfileWIndow;
|
||||
// ProfileWindow profile = new ProfileWindow(this, auth[0]);
|
||||
// tl();
|
||||
|
||||
/**
|
||||
* Notification loop
|
||||
|
@ -100,17 +126,29 @@ public final class Connection : Thread
|
|||
{
|
||||
/* Receive a notification */
|
||||
byte[] notificationData = client.awaitNotification();
|
||||
writeln(notificationData);
|
||||
gprintln("A new notification has arrived");
|
||||
gprintln("Notification data: "~to!(string)(notificationData));
|
||||
|
||||
te();
|
||||
// import std.conv;
|
||||
// textArea.add(new Label(to!(string)(notificationData)));
|
||||
// textArea.showAll();
|
||||
|
||||
|
||||
process(notificationData);
|
||||
//gui.mainWindow.showAll();
|
||||
|
||||
// import gtk.InfoBar;
|
||||
// InfoBar notificationBar = new InfoBar();
|
||||
// notificationBar.add(new Label("Poes"));
|
||||
// notificationBar.setMessageType(GtkMessageType.INFO);
|
||||
// notificationBar
|
||||
|
||||
// box.add(notificationBar);
|
||||
// notificationBar.showAll();
|
||||
|
||||
notebookSwitcher.showAll();
|
||||
|
||||
|
||||
tl();
|
||||
|
||||
|
@ -118,24 +156,100 @@ public final class Connection : Thread
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Processes an incoming notification
|
||||
* accordingly
|
||||
*/
|
||||
private void process(byte[] data)
|
||||
{
|
||||
/* TODO: Implement me */
|
||||
|
||||
/* TODO: Check notification type */
|
||||
/* Get the notification type */
|
||||
ubyte notificationType = data[0];
|
||||
gprintln("NotificationType: "~to!(string)(notificationType));
|
||||
|
||||
/* For normal message (to channel or user) */
|
||||
if(notificationType == 0)
|
||||
{
|
||||
/* TODO: Decode using tristanable */
|
||||
writeln("new message");
|
||||
/* TODO: Handle private messages */
|
||||
|
||||
/* Decode is a test for assuming channel message received */
|
||||
data = data[1..data.length];
|
||||
gprintln("Channel/User Notification: "~to!(string)(data));
|
||||
|
||||
|
||||
|
||||
/* If this is a new message channel notification */
|
||||
if(data[0] == 0)
|
||||
{
|
||||
gprintln("New channel message received", DebugType.WARNING);
|
||||
|
||||
/* Decode the [usernameLength, username] */
|
||||
ubyte usernameLength = data[1];
|
||||
gprintln("ChannelMessage: (Username length): "~to!(string)(usernameLength));
|
||||
string username = cast(string)data[2..2+usernameLength];
|
||||
gprintln("ChannelMessage: (Username): "~username);
|
||||
|
||||
/* Decode the [channelLength, channel] */
|
||||
ubyte channelLength = data[2+usernameLength];
|
||||
gprintln("ChannelMessage: (Channel length): "~to!(string)(channelLength));
|
||||
string channel = cast(string)data[2+usernameLength+1..2+usernameLength+1+channelLength];
|
||||
gprintln("ChannelMessage: (Channel): "~channel);
|
||||
|
||||
findChannel(channel).receiveMessage(username, cast(string)data[2+usernameLength+1+channelLength..data.length]);
|
||||
}
|
||||
/* If this is a new direct message notification */
|
||||
else if(data[0] == 1)
|
||||
{
|
||||
gprintln("New direct message received", DebugType.WARNING);
|
||||
|
||||
/* Decode the [usernameLength, username] (username here is recipient's) */
|
||||
ubyte recipientLength = data[1];
|
||||
gprintln("DirectMessage: (Recipient length): "~to!(string)(recipientLength));
|
||||
string recipient = cast(string)data[2..2+recipientLength];
|
||||
gprintln("DirectMessage: (Recipient): "~recipient);
|
||||
|
||||
/* Decode the [usernameLength, username] (username here is sender's) */
|
||||
ubyte sendersLength = data[2+recipientLength];
|
||||
gprintln("DirectMessage: (Sender length): "~to!(string)(sendersLength));
|
||||
string sender = cast(string)data[2+recipientLength+1..2+recipientLength+1+sendersLength];
|
||||
gprintln("DirectMessage: (Sender): "~sender);
|
||||
|
||||
|
||||
|
||||
/* The message is the remainder */
|
||||
string message = cast(string)data[2+recipientLength+1+sendersLength..data.length];
|
||||
gprintln("DirectMessage: (Message): "~message);
|
||||
|
||||
/**
|
||||
* TODO: DIfferes from channels, channels we never get delivered those we have no tab for as we haven't joined them
|
||||
* and because server side knows we haven't joined iot we don't receive the notifivcaiton, eher however, there is no
|
||||
* user tab possibly yet, so we will need to add it our selves */
|
||||
User userArea = findUser(sender);
|
||||
|
||||
if(userArea)
|
||||
{
|
||||
userArea.receiveMessage(sender, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add a new UserArea which will generate a new tab for us */
|
||||
addDirectMessage_unsafe(sender);
|
||||
|
||||
/* The above statement adds an entry for us, now let's find the added UserArea */
|
||||
userArea = findUser(sender);
|
||||
|
||||
/* Now let's add the direct message */
|
||||
userArea.receiveMessage(sender, message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Handle this */
|
||||
gprintln("FOk");
|
||||
}
|
||||
|
||||
}
|
||||
/* Channel notification (ntype=1) */
|
||||
else if(notificationType == 1)
|
||||
|
@ -186,7 +300,168 @@ public final class Connection : Thread
|
|||
}
|
||||
|
||||
|
||||
private void addUserDM(User newUser)
|
||||
{
|
||||
/* TODO: However this we need to mutex for the areas as we could recieve a new message by watcher which adds for us */
|
||||
chansLock.lock();
|
||||
areas ~= newUser;
|
||||
chansLock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new tab for a new direct message
|
||||
*
|
||||
* (To be called by a handler, which auto-mutexes)
|
||||
*
|
||||
* 1. Will add a new area
|
||||
* 2. Will add a new tab to the notebook switcher
|
||||
* 3. Will switch the current tab to said tab
|
||||
*/
|
||||
public void addDirectMessage_unsafe(string username)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
/* TODO: Get box over here etc. */
|
||||
|
||||
gprintln("Henlo begi");
|
||||
|
||||
/* Check if we have joined this user already */
|
||||
User foundUser = findUser(username);
|
||||
|
||||
gprintln("Henlo");
|
||||
|
||||
/* If we have joined this user before */
|
||||
if(foundUser)
|
||||
{
|
||||
/* TODO: Switch to */
|
||||
writeln("nope time: "~username);
|
||||
|
||||
|
||||
}
|
||||
/* If we haven't joined this user before */
|
||||
else
|
||||
{
|
||||
/* Create the new User area */
|
||||
User newUser = new User(this, username);
|
||||
|
||||
/* Add the user */
|
||||
addUserDM(newUser);
|
||||
|
||||
/* Set as the `foundChannel` */
|
||||
foundUser = newUser;
|
||||
|
||||
/* Get the Widgets container for this channel and add a tab for it */
|
||||
notebookSwitcher.add(newUser.getBox());
|
||||
notebookSwitcher.setTabReorderable(newUser.getBox(), true);
|
||||
notebookSwitcher.setTabLabelText(newUser.getBox(), newUser.getUsername());
|
||||
|
||||
writeln("hdsjghjsd");
|
||||
|
||||
writeln("first time: "~username);
|
||||
|
||||
// /* Get the user's list */
|
||||
// newChannel.populateUsersList();
|
||||
}
|
||||
|
||||
/* Render recursively all children of the container and then the container itself */
|
||||
box.showAll();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to find the User object you are looking for
|
||||
*/
|
||||
public User findUser(string username)
|
||||
{
|
||||
User result;
|
||||
|
||||
chansLock.lock();
|
||||
|
||||
/**
|
||||
* Loop through each MessageArea and only inspect those
|
||||
* whose type is `Channel`
|
||||
*/
|
||||
foreach(MessageArea area; areas)
|
||||
{
|
||||
|
||||
/* Make sure the object is of type `Channel` */
|
||||
if(typeid(area) == typeid(User))
|
||||
{
|
||||
/* Down-cast */
|
||||
User user = cast(User)area;
|
||||
|
||||
/* Find the matching channel */
|
||||
if(cmp(user.getUsername(), username) == 0)
|
||||
{
|
||||
result = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import std.stdio;
|
||||
writeln("\""~username~"\"");
|
||||
|
||||
|
||||
chansLock.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void joinChannel(string channelName)
|
||||
{
|
||||
/* Check if we have joined this channel already */
|
||||
Channel foundChannel = findChannel(channelName);
|
||||
|
||||
/* If we have joined this channel before */
|
||||
if(foundChannel)
|
||||
{
|
||||
/* TODO: Switch to */
|
||||
writeln("nope time: "~channelName);
|
||||
|
||||
|
||||
}
|
||||
/* If we haven't joined this channel before */
|
||||
else
|
||||
{
|
||||
/* Join the channel */
|
||||
client.join(channelName);
|
||||
|
||||
/* Create the Channel object */
|
||||
Channel newChannel = new Channel(this, channelName);
|
||||
|
||||
/* Add the channel */
|
||||
addChannel(newChannel);
|
||||
|
||||
/* Set as the `foundChannel` */
|
||||
foundChannel = newChannel;
|
||||
|
||||
/* Get the Widgets container for this channel and add a tab for it */
|
||||
notebookSwitcher.add(newChannel.getBox());
|
||||
notebookSwitcher.setTabReorderable(newChannel.getBox(), true);
|
||||
notebookSwitcher.setTabLabelText(newChannel.getBox(), newChannel.getName());
|
||||
|
||||
writeln("hdsjghjsd");
|
||||
|
||||
writeln("first time: "~channelName);
|
||||
|
||||
/* Get the user's list */
|
||||
newChannel.populateUsersList();
|
||||
}
|
||||
|
||||
/* Render recursively all children of the container and then the container itself */
|
||||
box.showAll();
|
||||
}
|
||||
|
||||
|
||||
private void channelList()
|
||||
|
@ -196,6 +471,11 @@ public final class Connection : Thread
|
|||
tl();
|
||||
}
|
||||
|
||||
public DClient getClient()
|
||||
{
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all channels and displays them
|
||||
*
|
||||
|
@ -214,106 +494,90 @@ public final class Connection : Thread
|
|||
}
|
||||
}
|
||||
|
||||
private Channel findChannel(string channelName)
|
||||
/**
|
||||
* Attempts to find the Channel object you are looking for
|
||||
*/
|
||||
public Channel findChannel(string channelName)
|
||||
{
|
||||
Channel result;
|
||||
|
||||
chansLock.lock();
|
||||
|
||||
foreach(Channel channel; chans)
|
||||
/**
|
||||
* Loop through each MessageArea and only inspect those
|
||||
* whose type is `Channel`
|
||||
*/
|
||||
foreach(MessageArea area; areas)
|
||||
{
|
||||
if(cmp(channel.getName(), channelName) == 0)
|
||||
|
||||
/* Make sure the object is of type `Channel` */
|
||||
if(typeid(area) == typeid(Channel))
|
||||
{
|
||||
result = channel;
|
||||
break;
|
||||
/* Down-cast */
|
||||
Channel channel = cast(Channel)area;
|
||||
|
||||
/* Find the matching channel */
|
||||
if(cmp(channel.getName(), channelName) == 0)
|
||||
{
|
||||
result = channel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import std.stdio;
|
||||
writeln("\""~channelName~"\"");
|
||||
|
||||
|
||||
chansLock.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addChannel(Channel newChannel)
|
||||
/**
|
||||
* Adds the given channel to the tarcking list
|
||||
*
|
||||
* This adds the Channel object to the list of
|
||||
* channels joined
|
||||
*
|
||||
* TODO: Migrate the gui.d channel join selectChannel
|
||||
* here
|
||||
* NOTE: You must manually join it though
|
||||
*/
|
||||
public void addChannel(Channel newChannel)
|
||||
{
|
||||
/* Add the channel to the `chans` tracking list */
|
||||
chansLock.lock();
|
||||
|
||||
chans ~= newChannel;
|
||||
|
||||
areas ~= newChannel;
|
||||
chansLock.unlock();
|
||||
|
||||
/* Add the channel to the channels list (sidebar) */
|
||||
writeln("Adding channel "~newChannel.getName());
|
||||
Label babaBooey = new Label(newChannel.getName()); /* TODO: Fuck Pango, fix here but yeah _ */
|
||||
babaBooey.setUseMarkup(false);
|
||||
babaBooey.setText(newChannel.getName());
|
||||
channels.add(babaBooey);
|
||||
}
|
||||
|
||||
private void selectChannel(ListBox s)
|
||||
/**
|
||||
* Called when you select a channel in the sidebar
|
||||
*
|
||||
* This moves you to the correct notebook tab for
|
||||
* that channel
|
||||
*/
|
||||
private void viewChannel(ListBox s)
|
||||
{
|
||||
/* Get the name of the channel selected */
|
||||
string channelSelected = (cast(Label)(s.getSelectedRow().getChild())).getText();
|
||||
|
||||
/* Check if we have joined this channel already */
|
||||
Channel foundChannel = findChannel(channelSelected);
|
||||
|
||||
/* If we have joined this channel before */
|
||||
if(foundChannel)
|
||||
{
|
||||
/* TODO: Switch to */
|
||||
writeln("nope time: "~channelSelected);
|
||||
|
||||
|
||||
}
|
||||
/* If we haven't joined this channel before */
|
||||
else
|
||||
{
|
||||
/* Join the channel */
|
||||
client.join(channelSelected);
|
||||
|
||||
/* Create the Channel object */
|
||||
Channel newChannel = new Channel(client, channelSelected);
|
||||
|
||||
/* Add the channel */
|
||||
addChannel(newChannel);
|
||||
|
||||
/* Set as the `foundChannel` */
|
||||
foundChannel = newChannel;
|
||||
|
||||
/* Get the Widgets container for this channel and add a tab for it */
|
||||
notebookSwitcher.add(newChannel.getBox());
|
||||
notebookSwitcher.setTabLabelText(newChannel.getBox(), newChannel.getName());
|
||||
|
||||
writeln("hdsjghjsd");
|
||||
|
||||
writeln("first time: "~channelSelected);
|
||||
|
||||
/* Get the user's list */
|
||||
newChannel.populateUsersList();
|
||||
}
|
||||
writeln(foundChannel is null);
|
||||
|
||||
/* Switch to the channel's pane */
|
||||
notebookSwitcher.setCurrentPage(foundChannel.getBox());
|
||||
|
||||
box.showAll();
|
||||
// notebookSwitcher.showAll();
|
||||
|
||||
/* TODO: Now add the widget */
|
||||
|
||||
// /* Set this as the currently selected channel */
|
||||
// currentChannel = channelSelected;
|
||||
// currentChannelLabel.setText(currentChannel);
|
||||
// // currentChannelLabel.show();
|
||||
// // box.show();
|
||||
|
||||
// /* Fetch a list of members */
|
||||
// string[] members = client.getMembers(channelSelected);
|
||||
|
||||
// /* Display the members */
|
||||
// users.removeAll();
|
||||
// foreach(string member; members)
|
||||
// {
|
||||
// users.add(new Label(member));
|
||||
// users.showAll();
|
||||
// }
|
||||
|
||||
// /* Clear the text area */
|
||||
// textArea.removeAll();
|
||||
// textArea.showAll();
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,7 +604,7 @@ public final class Connection : Thread
|
|||
|
||||
/* The channel's list */
|
||||
channels = new ListBox();
|
||||
channels.addOnSelectedRowsChanged(&selectChannel);
|
||||
channels.addOnSelectedRowsChanged(&viewChannel);
|
||||
|
||||
channelBox.add(new Label("Channels"));
|
||||
channelBox.add(channels);
|
||||
|
@ -371,6 +635,7 @@ public final class Connection : Thread
|
|||
// textBox.add(f);
|
||||
|
||||
notebookSwitcher = new Notebook();
|
||||
notebookSwitcher.setScrollable(true);
|
||||
//notebookSwitcher.add(newnew Label("test"));
|
||||
|
||||
box.add(channelBox);
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
module ConnectionAssistant;
|
||||
|
||||
/**
|
||||
* ConnectionAssistant
|
||||
*
|
||||
* This provides a graphical utility for
|
||||
* configuring new connections
|
||||
*/
|
||||
|
||||
import gtk.Assistant;
|
||||
import gtk.Label;
|
||||
import gtk.Box;
|
||||
import gtk.Entry;
|
||||
import gtk.Image;
|
||||
import gui;
|
||||
import std.conv;
|
||||
import std.string : cmp, strip;
|
||||
|
||||
public final class ConnectionAssistant : Assistant
|
||||
{
|
||||
/* Associated GUI instance */
|
||||
private GUI gui;
|
||||
|
||||
private Entry serverAddress;
|
||||
private Entry serverPort;
|
||||
private Entry username;
|
||||
private Entry password;
|
||||
|
||||
/* Summary box */
|
||||
Box summaryBox;
|
||||
|
||||
|
||||
this(GUI gui)
|
||||
{
|
||||
this.gui = gui;
|
||||
|
||||
initWindow();
|
||||
}
|
||||
|
||||
private void initWindow()
|
||||
{
|
||||
Assistant connectionAssistant = new Assistant();
|
||||
|
||||
/* Welcome page */
|
||||
Box welcomeBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
Image logo = new Image("user-available", GtkIconSize.DIALOG);
|
||||
logo.setPixelSize(250);
|
||||
welcomeBox.add(logo);
|
||||
|
||||
Label title = new Label("<span size=\"100\">Gustav</span>");
|
||||
title.setMarkup("<span font_desc=\"Open Sans Extrabold\" size=\"50000\">Gustav</span>");
|
||||
welcomeBox.add(title);
|
||||
|
||||
Label hello = new Label("");
|
||||
hello.setMarkup("<span size=\"15000\">Welcome to the connection setup</span>");
|
||||
welcomeBox.add(hello);
|
||||
|
||||
connectionAssistant.insertPage(welcomeBox, 0);
|
||||
connectionAssistant.setPageTitle(welcomeBox, "Welcome");
|
||||
|
||||
/* Configure a server */
|
||||
Box serverBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
Label serverBoxTitle = new Label("");
|
||||
serverBoxTitle.setMarkup("<span size=\"15000\">Server details</span>");
|
||||
serverBox.packStart(serverBoxTitle,0,0,30);
|
||||
serverAddress = new Entry();
|
||||
serverBox.add(serverAddress);
|
||||
serverAddress.setPlaceholderText("DNET server address");
|
||||
serverPort = new Entry();
|
||||
serverBox.add(serverPort);
|
||||
serverPort.setPlaceholderText("DNET server port");
|
||||
|
||||
|
||||
connectionAssistant.insertPage(serverBox, 1);
|
||||
connectionAssistant.setPageTitle(serverBox, "Network");
|
||||
|
||||
/* Configure your profile details */
|
||||
Box profileBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
Label profileBoxTitle = new Label("");
|
||||
profileBoxTitle.setMarkup("<span size=\"15000\">Account details</span>");
|
||||
profileBox.packStart(profileBoxTitle,0,0,30);
|
||||
username = new Entry();
|
||||
profileBox.add(username);
|
||||
username.setPlaceholderText("username");
|
||||
password = new Entry();
|
||||
profileBox.add(password);
|
||||
password.setPlaceholderText("password");
|
||||
|
||||
connectionAssistant.insertPage(profileBox, 2);
|
||||
connectionAssistant.setPageTitle(profileBox, "Account");
|
||||
|
||||
/* TODO: We should actually verify inputs before doing this */
|
||||
connectionAssistant.setPageComplete(welcomeBox, true);
|
||||
connectionAssistant.setPageComplete(serverBox, true);
|
||||
connectionAssistant.setPageComplete(profileBox, true);
|
||||
|
||||
|
||||
/* Summary */
|
||||
summaryBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
Label summaryBoxTitle = new Label("");
|
||||
summaryBoxTitle.setMarkup("<span size=\"15000\">Summary</span>");
|
||||
summaryBox.packStart(summaryBoxTitle,0,0,30);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
connectionAssistant.insertPage(summaryBox, 4);
|
||||
connectionAssistant.setPageType(summaryBox, GtkAssistantPageType.SUMMARY);
|
||||
|
||||
|
||||
connectionAssistant.addOnClose(&assistentComplete);
|
||||
connectionAssistant.addOnCancel(&assistenctCancel);
|
||||
|
||||
connectionAssistant.showAll();
|
||||
}
|
||||
|
||||
private void assistenctCancel(Assistant e)
|
||||
{
|
||||
/* TODO: Get this to work */
|
||||
/* TODO: The `.close()` doesn't seem to work */
|
||||
}
|
||||
|
||||
/* TODO: I want this code to run when we are on the summary page */
|
||||
private void kak()
|
||||
{
|
||||
/* Summary data */
|
||||
Label serverAddressLabel = new Label("");
|
||||
serverAddressLabel.setMarkup("<b>Server Address:</b> "~serverAddress.getBuffer().getText());
|
||||
|
||||
Label serverPortLabel = new Label("");
|
||||
serverPortLabel.setMarkup("<b>Server Port:</b> "~serverPort.getBuffer().getText());
|
||||
|
||||
Label accountUsername = new Label("");
|
||||
accountUsername.setMarkup("<b>Account username:</b> "~username.getBuffer().getText());
|
||||
|
||||
Label accountPassword = new Label("");
|
||||
accountPassword.setMarkup("<b>Account password:</b> "~password.getBuffer().getText());
|
||||
|
||||
|
||||
|
||||
summaryBox.add(serverAddressLabel);
|
||||
summaryBox.add(serverPortLabel);
|
||||
summaryBox.add(accountUsername);
|
||||
summaryBox.add(accountPassword);
|
||||
}
|
||||
|
||||
private void assistentComplete(Assistant)
|
||||
{
|
||||
/* Get the server details */
|
||||
string serverAddress = strip(serverAddress.getBuffer().getText());
|
||||
string serverPort = strip(serverPort.getBuffer().getText());
|
||||
|
||||
/* Get the account details */
|
||||
string accountUsername = strip(username.getBuffer().getText());
|
||||
string accountPassword = password.getBuffer().getText();
|
||||
|
||||
/* TODO: Check for emptiness */
|
||||
if(cmp(serverAddress, "") == 0 || cmp(serverPort, "") == 0 || cmp(accountUsername, "") == 0 || cmp(accountPassword, "") == 0)
|
||||
{
|
||||
/* TODO: Handle error here */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new Connection */
|
||||
gui.connectServer(serverAddress, to!(ushort)(serverPort), [accountUsername, accountPassword]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* Profile window
|
||||
*
|
||||
* User profile window
|
||||
*/
|
||||
|
||||
import Connection;
|
||||
import gtk.Window;
|
||||
import gtk.Label;
|
||||
import gtk.Image;
|
||||
import std.conv;
|
||||
import gtk.Box;
|
||||
|
||||
public final class ProfileWindow
|
||||
{
|
||||
private Connection connection;
|
||||
private string username;
|
||||
|
||||
this(Connection connection, string username)
|
||||
{
|
||||
this.connection = connection;
|
||||
this.username = username;
|
||||
|
||||
showWindow();
|
||||
}
|
||||
|
||||
private void showWindow()
|
||||
{
|
||||
/* Create the window with the username as the title */
|
||||
Window profileWindow = new Window(username);
|
||||
|
||||
/* Create a Box for contents */
|
||||
Box profileBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
|
||||
/* Create a Image for the profile picture */
|
||||
Image profileImage = new Image("/home/deavmi/Downloads/logo.png");
|
||||
profileBox.add(profileImage);
|
||||
// profileImage.
|
||||
|
||||
/* Create the username label */
|
||||
Label usernameTitle = new Label("");
|
||||
usernameTitle.setMarkup("<span size=\"20000\">"~username~"</span>");
|
||||
profileBox.add(usernameTitle);
|
||||
|
||||
|
||||
/* Display all props (keys) */
|
||||
string[] props = connection.getClient().getProperties(username);
|
||||
profileBox.add(new Label(to!(string)(props)));
|
||||
|
||||
/* Display all props (values) */
|
||||
string[] propValues;
|
||||
foreach(string property; props)
|
||||
{
|
||||
propValues ~= connection.getClient().getProperty(username, property);
|
||||
}
|
||||
profileBox.add(new Label(to!(string)(propValues)));
|
||||
|
||||
|
||||
|
||||
profileWindow.add(profileBox);
|
||||
profileWindow.showAll();
|
||||
// profileWindow.unmaximize();
|
||||
// profileWindow.setAttachedTo()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
module UserDirectory;
|
||||
|
||||
import Connection;
|
||||
import gtk.SearchBar;
|
||||
import gtk.Entry;
|
||||
import gtk.Window;
|
||||
|
||||
public final class UserDirectory
|
||||
{
|
||||
/* The associated connection */
|
||||
private Connection connection;
|
||||
|
||||
this(Connection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
|
||||
initWindow();
|
||||
}
|
||||
|
||||
private void initWindow()
|
||||
{
|
||||
Window userWindow = new Window(GtkWindowType.TOPLEVEL);
|
||||
userWindow.setTitle("User directory");
|
||||
|
||||
SearchBar searchBar = new SearchBar();
|
||||
Entry searchEntry = new Entry();
|
||||
searchEntry.setText("fsdhjsdfhjkdsfhjksdfhjk");
|
||||
// searchBar.handleEvent()
|
||||
searchBar.connectEntry(searchEntry);
|
||||
userWindow.add(searchBar);
|
||||
|
||||
|
||||
userWindow.showAll();
|
||||
}
|
||||
}
|
|
@ -1,29 +1,164 @@
|
|||
// import gtk.Tooltip;
|
||||
// import libdnet.dclient;
|
||||
// import gtk.Label;
|
||||
module UserNode;
|
||||
|
||||
// public final class UserNode
|
||||
// {
|
||||
// private Tooltip tooltip;
|
||||
// private DClient client;
|
||||
// private Label username;
|
||||
import Connection;
|
||||
import libdnet.client;
|
||||
import gtk.Box;
|
||||
import gtk.Button;
|
||||
import gtk.Image;
|
||||
import gtk.Label;
|
||||
import gtk.Tooltip;
|
||||
import gtk.Widget;
|
||||
import std.string;
|
||||
import ProfileWIndow;
|
||||
|
||||
// this(DClient client, Label username)
|
||||
// {
|
||||
// this.client = client;
|
||||
// this.username = username;
|
||||
public final class UserNode
|
||||
{
|
||||
private Connection connection;
|
||||
private string username;
|
||||
|
||||
// initialize();
|
||||
// }
|
||||
private Box box;
|
||||
|
||||
// private void initialize()
|
||||
// {
|
||||
// username.getToo
|
||||
// tooltip = new Tooltip(cast(GtkStruct*)username.getStruct());
|
||||
// }
|
||||
this(Connection connection, string username)
|
||||
{
|
||||
this.connection = connection;
|
||||
this.username = username;
|
||||
|
||||
// // public Tooltip getToolTip()
|
||||
// // {
|
||||
initBox();
|
||||
}
|
||||
|
||||
private void userButtonClick(Button)
|
||||
{
|
||||
/* Create a new ProfileWindow */
|
||||
ProfileWindow profileWindow = new ProfileWindow(connection, username);
|
||||
}
|
||||
|
||||
private void initBox()
|
||||
{
|
||||
/* Create a new Box */
|
||||
box = new Box(GtkOrientation.HORIZONTAL, 10);
|
||||
|
||||
/* Layout [Button (Prescence Icon)] - Label <username> - [Button (Reply Icon)]*/
|
||||
Button userButton = new Button();
|
||||
Image userButtonImg = new Image("user-available", GtkIconSize.BUTTON);
|
||||
userButton.setImage(userButtonImg);
|
||||
|
||||
// // }
|
||||
// }
|
||||
/* Set the handler for on click */
|
||||
userButton.addOnClicked(&userButtonClick);
|
||||
|
||||
/* Create a label */
|
||||
Label userLabel = new Label(username);
|
||||
|
||||
/* Enable the tooltip */
|
||||
userLabel.setHasTooltip(true);
|
||||
|
||||
/* Set the handler to run on hover */
|
||||
userLabel.addOnQueryTooltip(&userLabelHoverHandler);
|
||||
|
||||
/* TODO: Implement me */
|
||||
|
||||
/* Add both components */
|
||||
box.add(userButton);
|
||||
box.add(userLabel);
|
||||
|
||||
|
||||
/* Add the direct message button */
|
||||
Button messageButton = new Button();
|
||||
Image messageButtonImg = new Image("mail-forward", GtkIconSize.BUTTON);
|
||||
messageButton.setImage(messageButtonImg);
|
||||
|
||||
/* Set the handler for on click */
|
||||
messageButton.addOnClicked(&newDirectMessage);
|
||||
|
||||
box.add(messageButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the handler for when the "direct message" button is clicked
|
||||
*
|
||||
* It will call `addDirectMessage_unsafe` with the username specified
|
||||
*/
|
||||
private void newDirectMessage(Button)
|
||||
{
|
||||
connection.addDirectMessage_unsafe(username);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Event handler to be run when you hover over a user's
|
||||
* username in the Users sidebar list which will show
|
||||
* the status as text (and in an icon format), the user's
|
||||
* username and also their status message
|
||||
*/
|
||||
private bool userLabelHoverHandler(int, int, bool, Tooltip tooltip, Widget userLabel)
|
||||
{
|
||||
/* Get the client */
|
||||
DClient client = connection.getClient();
|
||||
|
||||
/* The username hovered over */
|
||||
string userHover = (cast(Label)userLabel).getText();
|
||||
|
||||
/* The final tooltip */
|
||||
string toolTipText = "<b>"~userHover~"</b>";
|
||||
|
||||
/* Check if there is a `precensce` message */
|
||||
if(client.isProperty(userHover, "pres"))
|
||||
{
|
||||
/* Fetch the precensce */
|
||||
string prescence = client.getProperty(userHover, "pres");
|
||||
|
||||
/* Set the icon */
|
||||
tooltip.setIconFromIconName(statusToGtkIcon(prescence), GtkIconSize.DIALOG);
|
||||
|
||||
/* Append the precesnee to the tooltip text */
|
||||
toolTipText ~= "\n"~prescence;
|
||||
}
|
||||
|
||||
/* Check if there is a `status` message */
|
||||
if(client.isProperty(userHover, "status"))
|
||||
{
|
||||
/* Next is status message */
|
||||
string status = client.getProperty(userHover, "status");
|
||||
|
||||
/* Append the status to the tooltip text */
|
||||
toolTipText ~= "\n<i>"~status~"</i>";
|
||||
}
|
||||
|
||||
/* Set the tooltip text */
|
||||
tooltip.setMarkup(toolTipText);
|
||||
|
||||
/* TODO: Point of return value? */
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static string statusToGtkIcon(string status)
|
||||
{
|
||||
/* The GTK icon */
|
||||
string gtkIcon = "image-missing";
|
||||
|
||||
if(cmp(status, "available") == 0)
|
||||
{
|
||||
gtkIcon = "user-available";
|
||||
}
|
||||
else if(cmp(status, "away") == 0)
|
||||
{
|
||||
gtkIcon = "user-away";
|
||||
}
|
||||
else if(cmp(status, "busy") == 0)
|
||||
{
|
||||
gtkIcon = "user-busy";
|
||||
}
|
||||
/* TODO: This doesn't make sense */
|
||||
else if(cmp(status, "offline") == 0)
|
||||
{
|
||||
gtkIcon = "user-offline";
|
||||
}
|
||||
|
||||
return gtkIcon;
|
||||
}
|
||||
|
||||
public Box getBox()
|
||||
{
|
||||
return box;
|
||||
/* TODO: Implement me */
|
||||
}
|
||||
}
|
60
source/app.d
60
source/app.d
|
@ -18,67 +18,14 @@ import gdk.Threads : threadsEnter, threadsLeave;
|
|||
|
||||
import gtk.SelectionData;
|
||||
import gtk.Widget;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Initialize the framework with no arguments */
|
||||
string[] args;
|
||||
Main.initMultiThread(args);
|
||||
|
||||
// threadsEnter();
|
||||
|
||||
// /* Create the main window */
|
||||
// MainWindow main = new MainWindow("unnamed");
|
||||
|
||||
|
||||
|
||||
// Box grid = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
// MenuBar menu = new MenuBar();
|
||||
|
||||
|
||||
// grid.add(menu);
|
||||
|
||||
// MenuItem fileMenu = new MenuItem("unamed");
|
||||
|
||||
// MenuItem thing1 = new MenuItem("poes");
|
||||
// Menu bruh = new Menu();
|
||||
// bruh.add(thing1);
|
||||
// fileMenu.setSubmenu(bruh);
|
||||
|
||||
// menu.add(fileMenu);
|
||||
// menu.add(new MenuItem("bruh"));
|
||||
|
||||
|
||||
// /* Status bar */
|
||||
// Statusbar statusBar = new Statusbar();
|
||||
|
||||
// statusBar.add(new Label("Gustav: Not connected"));
|
||||
|
||||
// grid.add(new Label("poo"));
|
||||
|
||||
// ListBox channels = new ListBox();
|
||||
|
||||
// Notebook tabs = new Notebook();
|
||||
// tabs.add(channels);
|
||||
// grid.add(tabs);
|
||||
|
||||
// grid.packEnd(statusBar, false, false, 0);
|
||||
|
||||
// Label k = new Label("dhjhfdjfhfjk");
|
||||
// channels.add(k);
|
||||
|
||||
// main.add(grid);
|
||||
|
||||
// /* Display the window and all its components */
|
||||
// main.showAll();
|
||||
|
||||
// k.setText("peoe");
|
||||
|
||||
// tabs.appendPage(new Label("lol"), "server2");
|
||||
|
||||
// main.showAll();
|
||||
|
||||
|
||||
|
||||
GUI gui = new GUI();
|
||||
gui.start();
|
||||
|
@ -86,9 +33,6 @@ void main()
|
|||
|
||||
/* Start the event loop */
|
||||
Main.run();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
/**
|
||||
* Channel
|
||||
*
|
||||
* Represents a channel which is a collection
|
||||
* of the channel name the users list widget,
|
||||
* the title widget and the chat list box widget
|
||||
* along with the input box state
|
||||
*/
|
||||
|
||||
module areas.Channel;
|
||||
|
||||
import gtk.Box;
|
||||
import gtk.ListBox;
|
||||
import gtk.Label;
|
||||
import gtk.TextView;
|
||||
import libdnet.client;
|
||||
import gtk.Label;
|
||||
import std.string;
|
||||
import gtk.Button;
|
||||
import gtk.Tooltip;
|
||||
import gtk.Widget;
|
||||
import gtk.ScrolledWindow;
|
||||
import gtk.Button;
|
||||
import gtk.Entry;
|
||||
import UserNode;
|
||||
|
||||
import pango.PgAttributeList;
|
||||
import pango.PgAttribute;
|
||||
import Connection;
|
||||
|
||||
import gogga;
|
||||
import areas.MessageArea;
|
||||
|
||||
public final class Channel : MessageArea
|
||||
{
|
||||
private DClient client;
|
||||
private Connection connection;
|
||||
|
||||
/**
|
||||
* Channel details
|
||||
*/
|
||||
private string channelName;
|
||||
|
||||
/**
|
||||
* UI components
|
||||
*
|
||||
* Users's box
|
||||
* - Label users
|
||||
* - ListBox users
|
||||
*/
|
||||
private ListBox users;
|
||||
private ListBox textArea;
|
||||
private Entry textInput;
|
||||
|
||||
/* TODO: No mutexes should be needed (same precaution) as the GTK lock provides safety */
|
||||
private string[] usersString;
|
||||
|
||||
this(Connection connection, string channelName)
|
||||
{
|
||||
this.client = connection.getClient();
|
||||
this.connection = connection;
|
||||
this.channelName = channelName;
|
||||
|
||||
initializeBox();
|
||||
}
|
||||
|
||||
private void initializeBox()
|
||||
{
|
||||
box = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
/* The user's box */
|
||||
Box userBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* The user's list */
|
||||
users = new ListBox();
|
||||
|
||||
userBox.add(new Label("Users"));
|
||||
|
||||
// import gtk.Expander;
|
||||
// Expander g = new Expander("Bruh");
|
||||
// g.setExpanded(true)
|
||||
// g.add(users);
|
||||
userBox.add(users);
|
||||
|
||||
/* The text box */
|
||||
Box textBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Channel title */
|
||||
Label channelTitleLabel = new Label(channelName);
|
||||
channelTitleLabel.setMarkup("<span size=\"large\"><b>"~channelName~"</b></span>");
|
||||
textBox.add(channelTitleLabel);
|
||||
|
||||
/* The messages box */
|
||||
textArea = new ListBox();
|
||||
ScrolledWindow scrollTextChats = new ScrolledWindow(textArea);
|
||||
textBox.add(scrollTextChats);
|
||||
|
||||
|
||||
/* The Box for the whole |attach button| text field| send button| */
|
||||
Box textInputBox = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
import gtk.Image;
|
||||
|
||||
/* The attachment button */
|
||||
Button attachFileButton = new Button("Upload");
|
||||
Image attachFileButtonIcon = new Image("user-available", GtkIconSize.BUTTON); /* TODO: Fix icon now showing */
|
||||
attachFileButton.setImage(attachFileButtonIcon);
|
||||
attachFileButton.addOnClicked(&uploadFileDialog);
|
||||
textInputBox.add(attachFileButton);
|
||||
|
||||
/* The text input */
|
||||
textInput = new Entry();
|
||||
textInput.addOnActivate(&sendMessageEnter);
|
||||
textInput.addOnChanged(&textChangd);
|
||||
|
||||
textInputBox.packStart(textInput,1,1,0);
|
||||
|
||||
|
||||
/* The send button */
|
||||
Button sendButton = new Button("Send");
|
||||
sendButton.addOnClicked(&sendMessageBtn);
|
||||
textInputBox.add(sendButton);
|
||||
textBox.add(textInputBox);
|
||||
|
||||
box.add(textBox);
|
||||
box.packEnd(userBox,0,0,0);
|
||||
|
||||
textBox.setChildPacking(scrollTextChats, true, true, 0, GtkPackType.START);
|
||||
box.setChildPacking(textBox, true, true, 0, GtkPackType.START);
|
||||
|
||||
}
|
||||
|
||||
private void uploadFileDialog(Button e)
|
||||
{
|
||||
import gtk.FileChooserDialog; /* TODO: Set parent */
|
||||
FileChooserDialog fileChooser = new FileChooserDialog("Send file to "~channelName, null, FileChooserAction.OPEN);
|
||||
fileChooser.run();
|
||||
gprintln("Selected file: "~fileChooser.getFilename());
|
||||
}
|
||||
|
||||
import gtk.EditableIF;
|
||||
private void textChangd(EditableIF)
|
||||
{
|
||||
/* If the text box just became empty stop ssending typing notifications */
|
||||
/* Send typing stats */
|
||||
// client.sendIsTyping(channelName, true);
|
||||
/* TODO: Client implement wiht different tag? */
|
||||
}
|
||||
|
||||
private void sendMessageEnter(Entry)
|
||||
{
|
||||
/* Retrieve the message */
|
||||
string message = textInput.getBuffer().getText();
|
||||
|
||||
/* TODO: Add the message to our log (as it won't be delivered to us) */
|
||||
sendMessage(message);
|
||||
|
||||
/* Send the message */
|
||||
client.sendMessage(0, channelName, message);
|
||||
|
||||
/* Clear the text box */
|
||||
textInput.getBuffer().setText("",0);
|
||||
|
||||
box.showAll();
|
||||
}
|
||||
|
||||
private void sendMessageBtn(Button)
|
||||
{
|
||||
/* Retrieve the message */
|
||||
string message = textInput.getBuffer().getText();
|
||||
|
||||
/* TODO: Add the message to our log (as it won't be delivered to us) */
|
||||
sendMessage(message);
|
||||
|
||||
/* Send the message */
|
||||
client.sendMessage(0, channelName, message);
|
||||
|
||||
/* Clear the text box */
|
||||
textInput.getBuffer().setText("",0);
|
||||
|
||||
box.showAll();
|
||||
}
|
||||
|
||||
public string getName()
|
||||
{
|
||||
return channelName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private Box getUserListItem(string username)
|
||||
{
|
||||
/* This is an item for a username in this Channel's user list */
|
||||
Box box = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
|
||||
import gtk.IconView;
|
||||
IconView icon = new IconView();
|
||||
import gtk.StatusIcon;
|
||||
StatusIcon d = new StatusIcon("user-available");
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
// private bool userLabelPopup(Widget)
|
||||
// {
|
||||
// import std.stdio;
|
||||
// writeln("NOWNOWNOWNOWNOW");
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
public void populateUsersList()
|
||||
{
|
||||
string[] memberList = client.getMembers(channelName);
|
||||
|
||||
foreach(string member; memberList)
|
||||
{
|
||||
/* Create the user entry in the list */
|
||||
UserNode userNode = new UserNode(connection, member);
|
||||
users.add(userNode.getBox());
|
||||
|
||||
/* Add the user to the tracking list */
|
||||
usersString~=member;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void channelJoin(string username)
|
||||
{
|
||||
/* The label to add */
|
||||
Label joinLabel = new Label("--> "~username~" joined the channel");
|
||||
joinLabel.setHalign(GtkAlign.START);
|
||||
PgAttributeList joinLabelAttrs = new PgAttributeList();
|
||||
PgAttribute joinLabelAttr = PgAttribute.styleNew(PangoStyle.ITALIC);
|
||||
joinLabelAttrs.insert(joinLabelAttr);
|
||||
joinLabel.setAttributes(joinLabelAttrs);
|
||||
|
||||
/* Add join message to message log */
|
||||
textArea.add(joinLabel);
|
||||
|
||||
/* Create the user entry in the list */
|
||||
UserNode userNode = new UserNode(connection, username);
|
||||
users.add(userNode.getBox());
|
||||
|
||||
/* Add the user to the tracking list */
|
||||
usersString~=username;
|
||||
}
|
||||
|
||||
public void channelLeave(string username)
|
||||
{
|
||||
/* The label to add */
|
||||
Label leaveLabel = new Label("<-- "~username~" left the channel");
|
||||
leaveLabel.setHalign(GtkAlign.START);
|
||||
PgAttributeList leaveLabelAttrs = new PgAttributeList();
|
||||
PgAttribute leaveLabelAttr = PgAttribute.styleNew(PangoStyle.ITALIC);
|
||||
leaveLabelAttrs.insert(leaveLabelAttr);
|
||||
leaveLabel.setAttributes(leaveLabelAttrs);
|
||||
|
||||
/* Add leave message to message log */
|
||||
textArea.add(leaveLabel);
|
||||
|
||||
/* TODO: Better way with just removing one dude */
|
||||
|
||||
/* Remove the user form users list */
|
||||
string[] newUsers;
|
||||
|
||||
foreach(string currentUser; usersString)
|
||||
{
|
||||
if(cmp(currentUser, username))
|
||||
{
|
||||
newUsers ~= currentUser;
|
||||
}
|
||||
}
|
||||
|
||||
usersString = newUsers;
|
||||
|
||||
/* Clear list */
|
||||
users.removeAll();
|
||||
|
||||
foreach(string currentUser; usersString)
|
||||
{
|
||||
/* Create the user entry in the list */
|
||||
UserNode userNode = new UserNode(connection, currentUser);
|
||||
users.add(userNode.getBox());
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(string message)
|
||||
{
|
||||
/* TOOD: Pass in connection perhaps */
|
||||
string username = "Yourself";
|
||||
|
||||
/* Create the MessageBox */
|
||||
Box messageBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Create and add the username */
|
||||
Label usernameLabel = new Label("");
|
||||
usernameLabel.setMarkup("<b>"~username~"</b>");
|
||||
usernameLabel.setHalign(GtkAlign.END);
|
||||
messageBox.add(usernameLabel);
|
||||
|
||||
/* Create and add the message */
|
||||
Label messageLabel = new Label(message);
|
||||
messageLabel.setHalign(GtkAlign.END);
|
||||
messageLabel.setSelectable(true);
|
||||
messageBox.add(messageLabel);
|
||||
|
||||
/* Add the message to the log */
|
||||
textArea.add(messageBox);
|
||||
}
|
||||
|
||||
public void receiveMessage(string username, string message)
|
||||
{
|
||||
/* Create the MessageBox */
|
||||
Box messageBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Create and add the username */
|
||||
Label usernameLabel = new Label("");
|
||||
usernameLabel.setMarkup("<b>"~username~"</b>");
|
||||
usernameLabel.setHalign(GtkAlign.START);
|
||||
messageBox.add(usernameLabel);
|
||||
|
||||
/* Create and add the message */
|
||||
Label messageLabel = new Label(message);
|
||||
messageLabel.setHalign(GtkAlign.START);
|
||||
messageLabel.setSelectable(true);
|
||||
messageBox.add(messageLabel);
|
||||
|
||||
// import gtk.Image;
|
||||
// Image d = new Image("/home/deavmi/Downloads/5207740.jpg");
|
||||
// messageBox.add(d);
|
||||
|
||||
/* Add the message to the log */
|
||||
textArea.add(messageBox);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* MessageArea
|
||||
*
|
||||
* Represents the binding of a text entry, send button, user list (sometimes)
|
||||
* and message log - basically the place where you message a channel or someone
|
||||
*
|
||||
* The sub-classes are "Direct Message" and "Channel"
|
||||
*/
|
||||
|
||||
module areas.MessageArea;
|
||||
|
||||
import gtk.Box;
|
||||
|
||||
public class MessageArea
|
||||
{
|
||||
/* TODO: Implement me */
|
||||
|
||||
/* The area's Box (where everything is contained) */
|
||||
protected Box box;
|
||||
|
||||
public Box getBox()
|
||||
{
|
||||
return box;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
module areas.User;
|
||||
|
||||
import areas.MessageArea;
|
||||
|
||||
import gtk.Box;
|
||||
import gtk.ListBox;
|
||||
import gtk.Label;
|
||||
import gtk.TextView;
|
||||
import libdnet.client;
|
||||
import gtk.Label;
|
||||
import std.string;
|
||||
import gtk.Button;
|
||||
import gtk.Tooltip;
|
||||
import gtk.Widget;
|
||||
import gtk.ScrolledWindow;
|
||||
import gtk.Button;
|
||||
import gtk.Entry;
|
||||
import UserNode;
|
||||
|
||||
import pango.PgAttributeList;
|
||||
import pango.PgAttribute;
|
||||
import Connection;
|
||||
|
||||
import gogga;
|
||||
|
||||
public final class User : MessageArea
|
||||
{
|
||||
private DClient client;
|
||||
private Connection connection;
|
||||
|
||||
/**
|
||||
* Username
|
||||
*/
|
||||
private string username;
|
||||
|
||||
/**
|
||||
* UI components
|
||||
*
|
||||
*/
|
||||
// private ListBox users;
|
||||
private ListBox textArea;
|
||||
private Entry textInput;
|
||||
|
||||
|
||||
/* TODO: No mutexes should be needed (same precaution) as the GTK lock provides safety */
|
||||
// private string[] usersString;
|
||||
|
||||
this(Connection connection, string username)
|
||||
{
|
||||
this.client = connection.getClient();
|
||||
this.connection = connection;
|
||||
this.username = username;
|
||||
|
||||
initializeBox();
|
||||
}
|
||||
|
||||
public string getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
private void initializeBox()
|
||||
{
|
||||
box = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
// box.add(new Label("poes"));
|
||||
/* The text box */
|
||||
Box textBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Channel title */
|
||||
Label channelTitleLabel = new Label(username);
|
||||
channelTitleLabel.setMarkup("<span size=\"large\"><b>"~username~"</b></span>");
|
||||
textBox.add(channelTitleLabel);
|
||||
|
||||
/* The messages box */
|
||||
textArea = new ListBox();
|
||||
ScrolledWindow scrollTextChats = new ScrolledWindow(textArea);
|
||||
textBox.add(scrollTextChats);
|
||||
|
||||
|
||||
/* The Box for the whole |attach button| text field| send button| */
|
||||
Box textInputBox = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
import gtk.Image;
|
||||
|
||||
/* The attachment button */
|
||||
Button attachFileButton = new Button("Upload");
|
||||
Image attachFileButtonIcon = new Image("user-available", GtkIconSize.BUTTON); /* TODO: Fix icon now showing */
|
||||
attachFileButton.setImage(attachFileButtonIcon);
|
||||
attachFileButton.addOnClicked(&uploadFileDialog);
|
||||
textInputBox.add(attachFileButton);
|
||||
|
||||
/* The text input */
|
||||
textInput = new Entry();
|
||||
textInput.addOnActivate(&sendMessageEnter);
|
||||
textInput.addOnChanged(&textChangd);
|
||||
|
||||
textInputBox.packStart(textInput,1,1,0);
|
||||
|
||||
|
||||
/* The send button */
|
||||
Button sendButton = new Button("Send");
|
||||
sendButton.addOnClicked(&sendMessageBtn);
|
||||
textInputBox.add(sendButton);
|
||||
textBox.add(textInputBox);
|
||||
|
||||
box.add(textBox);
|
||||
// box.packEnd(userBox,0,0,0);
|
||||
|
||||
textBox.setChildPacking(scrollTextChats, true, true, 0, GtkPackType.START);
|
||||
box.setChildPacking(textBox, true, true, 0, GtkPackType.START);
|
||||
|
||||
}
|
||||
|
||||
|
||||
import gtk.EditableIF;
|
||||
private void textChangd(EditableIF)
|
||||
{
|
||||
/* If the text box just became empty stop ssending typing notifications */
|
||||
/* Send typing stats */
|
||||
// client.sendIsTyping(channelName, true);
|
||||
/* TODO: Client implement wiht different tag? */
|
||||
}
|
||||
|
||||
private void sendMessageEnter(Entry)
|
||||
{
|
||||
/* Retrieve the message */
|
||||
string message = textInput.getBuffer().getText();
|
||||
|
||||
/* TODO: Add the message to our log (as it won't be delivered to us) */
|
||||
sendMessage(message);
|
||||
|
||||
/* Send the message */
|
||||
client.sendMessage(1, username, message);
|
||||
|
||||
/* Clear the text box */
|
||||
textInput.getBuffer().setText("",0);
|
||||
|
||||
box.showAll();
|
||||
}
|
||||
|
||||
private void sendMessageBtn(Button)
|
||||
{
|
||||
/* Retrieve the message */
|
||||
string message = textInput.getBuffer().getText();
|
||||
|
||||
/* TODO: Add the message to our log (as it won't be delivered to us) */
|
||||
sendMessage(message);
|
||||
|
||||
/* Send the message */
|
||||
client.sendMessage(1, username, message);
|
||||
|
||||
/* Clear the text box */
|
||||
textInput.getBuffer().setText("",0);
|
||||
|
||||
box.showAll();
|
||||
}
|
||||
|
||||
public void sendMessage(string message)
|
||||
{
|
||||
/* TOOD: Pass in connection perhaps */
|
||||
string username = "Yourself";
|
||||
|
||||
/* Create the MessageBox */
|
||||
Box messageBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Create and add the username */
|
||||
Label usernameLabel = new Label("");
|
||||
usernameLabel.setMarkup("<b>"~username~"</b>");
|
||||
usernameLabel.setHalign(GtkAlign.END);
|
||||
messageBox.add(usernameLabel);
|
||||
|
||||
/* Create and add the message */
|
||||
Label messageLabel = new Label(message);
|
||||
messageLabel.setHalign(GtkAlign.END);
|
||||
messageLabel.setSelectable(true);
|
||||
messageBox.add(messageLabel);
|
||||
|
||||
/* Add the message to the log */
|
||||
textArea.add(messageBox);
|
||||
}
|
||||
|
||||
public void receiveMessage(string username, string message)
|
||||
{
|
||||
/* Create the MessageBox */
|
||||
Box messageBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Create and add the username */
|
||||
Label usernameLabel = new Label("");
|
||||
usernameLabel.setMarkup("<b>"~username~"</b>");
|
||||
usernameLabel.setHalign(GtkAlign.START);
|
||||
messageBox.add(usernameLabel);
|
||||
|
||||
/* Create and add the message */
|
||||
Label messageLabel = new Label(message);
|
||||
messageLabel.setHalign(GtkAlign.START);
|
||||
messageLabel.setSelectable(true);
|
||||
messageBox.add(messageLabel);
|
||||
|
||||
// import gtk.Image;
|
||||
// Image d = new Image("/home/deavmi/Downloads/5207740.jpg");
|
||||
// messageBox.add(d);
|
||||
|
||||
/* Add the message to the log */
|
||||
textArea.add(messageBox);
|
||||
}
|
||||
|
||||
private void uploadFileDialog(Button e)
|
||||
{
|
||||
import gtk.FileChooserDialog; /* TODO: Set parent */
|
||||
FileChooserDialog fileChooser = new FileChooserDialog("Send file to "~username, null, FileChooserAction.OPEN);
|
||||
fileChooser.run();
|
||||
gprintln("Selected file: "~fileChooser.getFilename());
|
||||
}
|
||||
}
|
540
source/gui.d
540
source/gui.d
|
@ -12,20 +12,39 @@ import gtk.Menu;
|
|||
import gtk.MenuItem;
|
||||
import std.stdio;
|
||||
import gtk.Statusbar;
|
||||
import gtk.Toolbar;
|
||||
import gtk.ToolButton;
|
||||
import gtk.ScrolledWindow;
|
||||
import gtk.SeparatorToolItem;
|
||||
import gtk.ToolItem;
|
||||
import gtk.SearchEntry;
|
||||
import gtk.Image;
|
||||
|
||||
import Connection;
|
||||
import areas.Channel;
|
||||
import std.socket;
|
||||
|
||||
import std.conv;
|
||||
|
||||
public class GUI : Thread
|
||||
{
|
||||
/* Main window (GUI homepage) */
|
||||
public MainWindow mainWindow;
|
||||
private MenuBar menuBar;
|
||||
private Toolbar toolbar;
|
||||
|
||||
private Box box;
|
||||
private Box welcomeBox;
|
||||
|
||||
public Notebook notebook;
|
||||
|
||||
|
||||
|
||||
private Statusbar statusBar;
|
||||
|
||||
|
||||
|
||||
|
||||
private Connection[] connections;
|
||||
|
||||
private ListBox list;
|
||||
|
@ -39,8 +58,10 @@ public class GUI : Thread
|
|||
private void worker()
|
||||
{
|
||||
initializeGUI();
|
||||
te();
|
||||
|
||||
|
||||
te();
|
||||
|
||||
tl();
|
||||
writeln("brg");
|
||||
while(true)
|
||||
|
@ -52,16 +73,64 @@ public class GUI : Thread
|
|||
private void initializeGUI()
|
||||
{
|
||||
initializeMainWindow();
|
||||
}
|
||||
|
||||
/* Test adding a connection */
|
||||
for(uint i = 0; i < 5; i++)
|
||||
{
|
||||
// connections ~= new Connection(this, parseAddress("0.0.0.0", 7777));
|
||||
}
|
||||
|
||||
connections ~= new Connection(this, parseAddress("0.0.0.0", 7777), ["testGustav1", "bruh"]);
|
||||
|
||||
/**
|
||||
* The welcome box is shown before
|
||||
* you have added any connections
|
||||
* (it takes place of the Notebook)
|
||||
* and shows information about the
|
||||
* application
|
||||
*
|
||||
* Once you make your first conneciton
|
||||
* it is removed and its space is taken
|
||||
* up by the Notebook
|
||||
*/
|
||||
private Box getWelcomeBox()
|
||||
{
|
||||
/* Create a vertically stacking Box */
|
||||
Box welcomeBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/* Add the logo */
|
||||
Image logo = new Image("user-available", GtkIconSize.DIALOG);
|
||||
logo.setPixelSize(250);
|
||||
welcomeBox.add(logo);
|
||||
|
||||
/* Create the welcome text */
|
||||
Label title = new Label("<span size=\"100\">Gustav</span>");
|
||||
title.setMarkup("<span font_desc=\"Open Sans Extrabold\" size=\"50000\">Gustav</span>");
|
||||
welcomeBox.add(title);
|
||||
|
||||
/* Create the welcome tagline */
|
||||
Label tagline = new Label("<span size=\"100\">Gustav</span>");
|
||||
tagline.setMarkup("<span size=\"30000\">GTK+ graphical DNET client</span>");
|
||||
welcomeBox.add(tagline);
|
||||
|
||||
Label findServersLabel = new Label("<a href=\"\">fok</a>");
|
||||
findServersLabel.setMarkup("<a href=\"\">Find some servers</a>");
|
||||
welcomeBox.add(findServersLabel);
|
||||
|
||||
Label configureConnectionsLabel = new Label("<a href=\"\">Configure connections</a>");
|
||||
configureConnectionsLabel.setMarkup("<a href=\"\">Configure connections</a>");
|
||||
configureConnectionsLabel.addOnActivateLink(&conifgureConnectionsAssistant);
|
||||
welcomeBox.add(configureConnectionsLabel);
|
||||
|
||||
Label connectGenesisLabel = new Label("<a href=\"\">Connect to the genesis server</a>");
|
||||
connectGenesisLabel.setMarkup("<span size=\"12000\"> <a href=\"\">Connect to the genesis server</a></span>");
|
||||
connectGenesisLabel.addOnActivateLink(&welcomeGenesisLabelClick);
|
||||
welcomeBox.add(connectGenesisLabel);
|
||||
|
||||
|
||||
|
||||
return welcomeBox;
|
||||
}
|
||||
|
||||
private bool welcomeGenesisLabelClick(string, Label)
|
||||
{
|
||||
connectServer("0.0.0.0", 7777, ["testGustav"~to!(string)(connections.length), "bruh"]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +153,7 @@ public class GUI : Thread
|
|||
* |component 1|
|
||||
* |component 2|
|
||||
*/
|
||||
Box box = new Box(GtkOrientation.VERTICAL, 1);
|
||||
box = new Box(GtkOrientation.VERTICAL, 1);
|
||||
|
||||
/**
|
||||
* Add needed components
|
||||
|
@ -93,11 +162,26 @@ public class GUI : Thread
|
|||
*/
|
||||
menuBar = initializeMenuBar();
|
||||
box.add(menuBar);
|
||||
notebook = new Notebook();
|
||||
box.add(notebook);
|
||||
|
||||
toolbar = getToolbar();
|
||||
box.add(toolbar);
|
||||
|
||||
/* Create the welcome box and set it */
|
||||
welcomeBox = getWelcomeBox();
|
||||
box.add(welcomeBox);
|
||||
|
||||
|
||||
|
||||
statusBar = new Statusbar();
|
||||
statusBar.add(new Label("Gustav: Bruh"));
|
||||
box.setChildPacking(notebook, true, true, 0, GtkPackType.START);
|
||||
// import gtk.IconView;
|
||||
// IconView j = new IconView();
|
||||
// j.set
|
||||
// statusBar.add(d);
|
||||
|
||||
|
||||
|
||||
|
||||
box.packEnd(statusBar, 0, 0, 0);
|
||||
//notebook.add(createServerTab());
|
||||
|
||||
|
@ -115,6 +199,380 @@ public class GUI : Thread
|
|||
writeln("unlock gui setup");
|
||||
}
|
||||
|
||||
private Toolbar getToolbar()
|
||||
{
|
||||
/* Create a new Toolbar */
|
||||
Toolbar toolbar = new Toolbar();
|
||||
|
||||
/* Status selector dropdown */
|
||||
/* TODO */
|
||||
|
||||
|
||||
/* Set available button */
|
||||
ToolButton setAvail = new ToolButton("");
|
||||
setAvail.setLabel("available");
|
||||
setAvail.setIconName("user-available");
|
||||
toolbar.add(setAvail);
|
||||
|
||||
/* Set away button */
|
||||
ToolButton setAway = new ToolButton("");
|
||||
setAway.setLabel("away");
|
||||
setAway.setIconName("user-away");
|
||||
toolbar.add(setAway);
|
||||
|
||||
/* Set busy button */
|
||||
ToolButton setBusy = new ToolButton("");
|
||||
setBusy.setLabel("busy");
|
||||
setBusy.setIconName("user-busy");
|
||||
toolbar.add(setBusy);
|
||||
|
||||
|
||||
/* Assign actions */
|
||||
setAvail.addOnClicked(&setStatus);
|
||||
setAway.addOnClicked(&setStatus);
|
||||
setBusy.addOnClicked(&setStatus);
|
||||
|
||||
|
||||
/* The status box */
|
||||
Entry statusBox = new Entry();
|
||||
statusBox.addOnActivate(&setStatusMessage);
|
||||
statusBox.setPlaceholderText("I'm currently...");
|
||||
ToolItem statusBoxItem = new ToolItem();
|
||||
statusBoxItem.add(statusBox);
|
||||
toolbar.add(statusBoxItem);
|
||||
|
||||
|
||||
/* Add a seperator */
|
||||
toolbar.add(new SeparatorToolItem());
|
||||
|
||||
|
||||
/* List channels button */
|
||||
ToolButton channelListButton = new ToolButton("");
|
||||
channelListButton.setIconName("emblem-documents");
|
||||
channelListButton.setTooltipText("List channels");
|
||||
channelListButton.addOnClicked(&listChannels);
|
||||
toolbar.add(channelListButton);
|
||||
|
||||
/* TODO: Join channel button */
|
||||
ToolButton joinChannelButton = new ToolButton("");
|
||||
joinChannelButton.setIconName("document-new");
|
||||
joinChannelButton.setTooltipText("Join channel");
|
||||
toolbar.add(joinChannelButton);
|
||||
|
||||
|
||||
/* TODO: Leave channel button */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SearchEntry dd = new SearchEntry();
|
||||
ToolItem j = new ToolItem();
|
||||
j.add(dd);
|
||||
toolbar.add(j);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
import gtk.Entry;
|
||||
import std.string;
|
||||
private void setStatusMessage(Entry f)
|
||||
{
|
||||
/* If there are no connections */
|
||||
if(!connections.length)
|
||||
{
|
||||
import gtk.MessageDialog;
|
||||
MessageDialog errorDialog = new MessageDialog(mainWindow, GtkDialogFlags.MODAL, GtkMessageType.ERROR, GtkButtonsType.CLOSE, false, "Cannot set status\n\nYou are not connected to a server");
|
||||
errorDialog.setIconName("user-available");
|
||||
// errorDialog.set
|
||||
errorDialog.run();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Get the current connection */
|
||||
Connection currentConnection = connections[notebook.getCurrentPage()];
|
||||
|
||||
/* Get the input text (removing leading and trailing whitespace) */
|
||||
string statusTextInput = f.getBuffer().getText();
|
||||
statusTextInput = strip(statusTextInput);
|
||||
|
||||
/* Set the text box to the stripped version */
|
||||
//f.getBuffer().setText(statusTextInput, cast(int)statusTextInput.length);
|
||||
|
||||
/* If the status text is empty */
|
||||
if(cmp(statusTextInput, "") == 0)
|
||||
{
|
||||
/* Delete the status property */
|
||||
currentConnection.getClient().deleteProperty("status");
|
||||
}
|
||||
/* If the status text is non empty */
|
||||
else
|
||||
{
|
||||
/* Set the status */
|
||||
currentConnection.getClient().setProperty("status", statusTextInput);
|
||||
}
|
||||
|
||||
//f.setInputHints(GtkInputHints.)
|
||||
|
||||
/* Defocus the currently focused widget which would always be me if you are hitting enter */
|
||||
mainWindow.setFocus(null);
|
||||
}
|
||||
|
||||
private void about(MenuItem)
|
||||
{
|
||||
import gtk.AboutDialog;
|
||||
AboutDialog about = new AboutDialog();
|
||||
|
||||
about.setVersion("21893");
|
||||
|
||||
/* TODO: License */
|
||||
/* TODO: Icon */
|
||||
/* TODO: Buttons or close */
|
||||
/* TODO: Set version based on compiler flag */
|
||||
|
||||
about.setLogoIconName("user-available");
|
||||
about.setArtists(["i wonder if I could commision an artwork from her"]);
|
||||
|
||||
/* Set all the information */
|
||||
about.setLicense("LICENSE GOES HERE");
|
||||
about.setComments("A clean GTK+ graphical DNET client");
|
||||
about.setWebsite("http://deavmi.assigned.network/docs/dnet/site");
|
||||
about.setDocumenters(["ss","fdsfsd"]);
|
||||
about.setAuthors(["Tristan B. Kildaire (Deavmi) - deavmi@disroot.org"]);
|
||||
|
||||
/* Show the about dialog */
|
||||
about.showAll();
|
||||
}
|
||||
|
||||
import gtk.Button;
|
||||
|
||||
/**
|
||||
* Returns a Box which contains channel list item
|
||||
*/
|
||||
|
||||
private class JoinButton : Button
|
||||
{
|
||||
private string channelName;
|
||||
this(string channelName)
|
||||
{
|
||||
this.channelName = channelName;
|
||||
}
|
||||
public string getChannelName()
|
||||
{
|
||||
return channelName;
|
||||
}
|
||||
}
|
||||
private Box channelItemList(Connection currentConnection, string channelName)
|
||||
{
|
||||
/* Create the main container */
|
||||
Box containerMain = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
|
||||
|
||||
|
||||
/* Add the channel label */
|
||||
Label channelLabel = new Label("");
|
||||
channelLabel.setHalign(GtkAlign.START);
|
||||
channelLabel.setMarkup("<b>"~channelName~"</b>");
|
||||
|
||||
/* Add the member count */
|
||||
ulong memberCount = currentConnection.getClient().getMemberCount(channelName);
|
||||
Label memberCountLabel = new Label("");
|
||||
memberCountLabel.setHalign(GtkAlign.START);
|
||||
memberCountLabel.setText(to!(string)(memberCount)~" members");
|
||||
|
||||
/* Create the channel box */
|
||||
Box channelBox = new Box(GtkOrientation.VERTICAL, 1);
|
||||
channelBox.add(channelLabel);
|
||||
channelBox.add(memberCountLabel);
|
||||
|
||||
/* Join button */
|
||||
JoinButton joinButton = new JoinButton(channelName);
|
||||
joinButton.setLabel("Join");
|
||||
|
||||
|
||||
|
||||
/* Add this then a button */
|
||||
containerMain.add(channelBox);
|
||||
containerMain.packEnd(joinButton,0,0,0);
|
||||
|
||||
|
||||
|
||||
joinButton.addOnClicked(&selectChannel);
|
||||
|
||||
|
||||
|
||||
/* TODO: COnsider adding member list */
|
||||
/* TODO: Seperate queue for dynamic updates to this list */
|
||||
containerMain.setTooltipMarkup("<b>"~channelName~"</b>\n"~to!(string)(memberCount)~" members\n\n"~to!(string)(currentConnection.getClient().getMembers(channelName)));
|
||||
|
||||
return containerMain;
|
||||
}
|
||||
|
||||
|
||||
private class JoinButtonCustom : Button
|
||||
{
|
||||
private Entry channelInputBox;
|
||||
|
||||
this(Entry channelInputBox)
|
||||
{
|
||||
/* Set the button's text to "Join" */
|
||||
super("Join");
|
||||
|
||||
/* Set the handler for the button */
|
||||
addOnClicked(&handler);
|
||||
|
||||
this.channelInputBox = channelInputBox;
|
||||
}
|
||||
|
||||
private void handler(Button)
|
||||
{
|
||||
/* Get the current connection */
|
||||
Connection currentConnection = connections[notebook.getCurrentPage()];
|
||||
|
||||
/* Get the name of the channel selected */
|
||||
string channelSelected = channelInputBox.getText();
|
||||
|
||||
/* Join the channel on this connection */
|
||||
currentConnection.joinChannel(channelSelected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List channels
|
||||
*
|
||||
* Brings up a window listing channels of the current server
|
||||
*/
|
||||
private void listChannels(ToolButton)
|
||||
{
|
||||
import gtk.Window;
|
||||
|
||||
/* Create the window */
|
||||
Window win = new Window(GtkWindowType.TOPLEVEL);
|
||||
|
||||
/* Create the list of channels */
|
||||
ListBox channelsList = new ListBox();
|
||||
win.add(new ScrolledWindow(channelsList));
|
||||
|
||||
|
||||
|
||||
|
||||
/* TODO: Temporary, REMOVE AFTWR TESTING (ADDED ON 27th of JAN 2021) */
|
||||
Box box = new Box(GtkOrientation.HORIZONTAL, 1);
|
||||
Entry customChannelEntry = new Entry();
|
||||
box.packStart(customChannelEntry, 1, 1, 1);
|
||||
box.add(new JoinButtonCustom(customChannelEntry));
|
||||
channelsList.add(box);
|
||||
|
||||
/* If there are no available connections */
|
||||
if(!connections.length)
|
||||
{
|
||||
import gtk.MessageDialog;
|
||||
MessageDialog errorDialog = new MessageDialog(mainWindow, GtkDialogFlags.MODAL, GtkMessageType.ERROR, GtkButtonsType.CLOSE, false, "Cannot list channels\n\nYou are not connected to a server");
|
||||
errorDialog.setIconName("user-available");
|
||||
// errorDialog.set
|
||||
errorDialog.run();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Get the current connection */
|
||||
Connection currentConnection = connections[notebook.getCurrentPage()];
|
||||
|
||||
/* Fetch the channels */
|
||||
string[] channels = currentConnection.getClient().list();
|
||||
|
||||
/* Add each channel */
|
||||
foreach(string channel; channels)
|
||||
{
|
||||
// channelsList.add(new Label(channel));
|
||||
channelsList.add(channelItemList(currentConnection, channel));
|
||||
writeln("bruh: "~channel);
|
||||
channelsList.showAll();
|
||||
}
|
||||
|
||||
/* TODO: Add handler for clicking label that lets you join the channel */
|
||||
// channelsList.addOnSelectedRowsChanged(&selectChannel);
|
||||
//channelsList.add
|
||||
|
||||
|
||||
win.showAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new window for connecting to a server
|
||||
*/
|
||||
private void connect(MenuItem)
|
||||
{
|
||||
import gtk.Window;
|
||||
|
||||
/* Create the window */
|
||||
Window win = new Window(GtkWindowType.TOPLEVEL);
|
||||
|
||||
|
||||
//import gtk.Text
|
||||
|
||||
|
||||
|
||||
win.showAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run when you select the 'Join' button next tio an already existing
|
||||
* channel in the channels list
|
||||
*/
|
||||
private void selectChannel(Button s)
|
||||
{
|
||||
/* Get the current connection */
|
||||
Connection currentConnection = connections[notebook.getCurrentPage()];
|
||||
|
||||
/* Get the name of the channel selected */
|
||||
string channelSelected = (cast(JoinButton)s).getChannelName(); //(cast(Label)(s.getSelectedRow().getChild())).getText();
|
||||
|
||||
/* Join the channel on this connection */
|
||||
currentConnection.joinChannel(channelSelected);
|
||||
}
|
||||
|
||||
private bool conifgureConnectionsAssistant(string, Label)
|
||||
{
|
||||
import ConnectionAssistant;
|
||||
ConnectionAssistant ass = new ConnectionAssistant(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void setStatus(ToolButton x)
|
||||
{
|
||||
/* If there are any available connections */
|
||||
if(connections.length)
|
||||
{
|
||||
/* Get the current connection */
|
||||
Connection currentConnection = connections[notebook.getCurrentPage()];
|
||||
|
||||
/* Set the status */
|
||||
currentConnection.getClient().setProperty("pres", x.getLabel());
|
||||
}
|
||||
/* If there are no connections */
|
||||
else
|
||||
{
|
||||
import gtk.MessageDialog;
|
||||
MessageDialog errorDialog = new MessageDialog(mainWindow, GtkDialogFlags.MODAL, GtkMessageType.ERROR, GtkButtonsType.CLOSE, false, "Cannot set prescence\n\nYou are not connected to a server");
|
||||
errorDialog.setIconName("user-available");
|
||||
// errorDialog.set
|
||||
errorDialog.run();
|
||||
}
|
||||
}
|
||||
|
||||
private MenuBar initializeMenuBar()
|
||||
{
|
||||
MenuBar menuBar = new MenuBar();
|
||||
|
@ -131,18 +589,40 @@ public class GUI : Thread
|
|||
connectItem.addOnActivate(&connectButton);
|
||||
gustavMenu.add(connectItem);
|
||||
|
||||
/* Connect v2 option */
|
||||
MenuItem connectItem2 = new MenuItem();
|
||||
connectItem2.setLabel("Connect");
|
||||
connectItem2.addOnActivate(&connect);
|
||||
gustavMenu.add(connectItem2);
|
||||
|
||||
|
||||
|
||||
/* Exit option */
|
||||
MenuItem exitItem = new MenuItem();
|
||||
exitItem.setLabel("Exit");
|
||||
exitItem.addOnActivate(&exitButton);
|
||||
gustavMenu.add(exitItem);
|
||||
|
||||
|
||||
/* Help menu */
|
||||
MenuItem helpMenuItem = new MenuItem();
|
||||
helpMenuItem.setLabel("Help");
|
||||
Menu helpMenu = new Menu();
|
||||
helpMenuItem.setSubmenu(helpMenu);
|
||||
|
||||
/* About option */
|
||||
MenuItem aboutItem = new MenuItem();
|
||||
aboutItem.setLabel("About");
|
||||
aboutItem.addOnActivate(&about);
|
||||
helpMenu.add(aboutItem);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Add all menues */
|
||||
menuBar.add(gustavMenuItem);
|
||||
menuBar.add(helpMenuItem);
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
@ -168,7 +648,41 @@ public class GUI : Thread
|
|||
|
||||
private void connectButton(MenuItem)
|
||||
{
|
||||
connections ~= new Connection(this, parseAddress("0.0.0.0", 7777), ["testGustav1", "bruh"]);
|
||||
connectServer("0.0.0.0", 7777, ["testGustav"~to!(string)(connections.length), "bruh"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the provided server,
|
||||
* add the tab as well
|
||||
*
|
||||
* NOTE: To be called only by a GTK signal
|
||||
* handler
|
||||
*/
|
||||
public void connectServer(string address, ushort port, string[] authDetails)
|
||||
{
|
||||
/**
|
||||
* If this is our first connection then
|
||||
* create a new Notebook which will
|
||||
* hold the connection/session tabs
|
||||
* and remove the welcome page
|
||||
*/
|
||||
if(!notebook)
|
||||
{
|
||||
notebook = new Notebook();
|
||||
notebook.setScrollable(true);
|
||||
box.add(notebook);
|
||||
box.setChildPacking(notebook, true, true, 0, GtkPackType.START);
|
||||
box.remove(welcomeBox);
|
||||
box.showAll();
|
||||
}
|
||||
|
||||
/* Create the new Connection */
|
||||
Connection newConnection = new Connection(this, parseAddress(address, port), authDetails);
|
||||
connections ~= newConnection;
|
||||
|
||||
// import UserDirectory;
|
||||
// UserDirectory d = new UserDirectory(newConnection);
|
||||
|
||||
}
|
||||
|
||||
private void shutdownConnections()
|
||||
|
|
Loading…
Reference in New Issue