Interface update and code improvements, translation
BIN
CodeField.png
Before Width: | Height: | Size: 7.8 KiB |
BIN
DecodedCode.png
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
DropSave.png
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 206 KiB |
BIN
ExampleCode.png
Normal file
After Width: | Height: | Size: 188 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 205 KiB |
46
README.md
|
@ -1,10 +1,48 @@
|
||||||
# JDarkroom
|
# JDarkroom
|
||||||
This is a simple, completely offline reimplementation of Darkroom website<br>
|
### ENG
|
||||||
that existed a while ago, but now it is offline. Using JDarkroom you can retrieve<br>
|
This is a simple, completely offline reimplementation of the Darkroom website that existed<br>
|
||||||
locker code in Akuda bar by dropping a save file here or by entering an Internet code.<br>
|
a while ago, but now it is offline. Using JDarkroom you can retrieve locker code in Akuda bar.<br>
|
||||||
|
There are two ways how you can do that:
|
||||||
|
- By dropping a save file here (slot[0-4].sav)
|
||||||
|
- Enter an Internet code that you can find at the bottom of the screen when you are about to save your game.<br>
|
||||||
|
|
||||||
|
Example of an Internet code: ```fCe\w9!iBXJ1ijn&```<br>
|
||||||
Both Russian and English game versions are supported.
|
Both Russian and English game versions are supported.
|
||||||
|
|
||||||
|
***A note***<br>
|
||||||
|
This app would not exist, if it was not this super helpful article: https://9214.github.io/13
|
||||||
|
|
||||||
|
Why did I make this if there are online websites that are much more similar to the original Darkroom?<br>
|
||||||
|
As the author of this article said, these can go offline at any time, but with this tool you don't have to<br>
|
||||||
|
worry about that, because this app will just be stored on your pc as a single file.
|
||||||
|
|
||||||
|
|
||||||
|
### РУС
|
||||||
|
Это простая, не требующая интернет-соединения программа, которая повторяет функционал сайта Darkroom,<br>
|
||||||
|
который существовал раньше, однако, теперь он больше не доступен. Используя JDarkroom вы можете получить код от шкафа в баре Акуда.<br>
|
||||||
|
Сделать это можно двумя способами:
|
||||||
|
- Перенести в окно программы файл сохранения (slot[0-4].sav)
|
||||||
|
- Ввести специальный Интернет-код, который вы можете найти внизу вашего экрана при сохранении игры.<br>
|
||||||
|
|
||||||
|
Пример Интернет-кода: ```fCe\w9!iBXJ1ijn&```<br>
|
||||||
|
Поддерживаются Английская и Русская версии игры.
|
||||||
|
|
||||||
|
***Заметка***<br>
|
||||||
|
Это приложение не существовало бы, если бы не эта суперполезная статья: https://9214.github.io/13
|
||||||
|
|
||||||
|
Зачем я создал это приложение, ведь уже существуют сайты, которые очень похожи на оригинальный Darkroom?<br>
|
||||||
|
Как сказал автор этой статьи, эти веб-сайты, так же как и оригинальный, могут быть отключены в любое время,<br>
|
||||||
|
но с этим приложением вам не стоит переживать, ведь оно просто будет находится у вас на компьютере в виде одного файла.
|
||||||
|
|
||||||
### Screenshots
|
### Screenshots
|
||||||
|
#### You can drop save file here:
|
||||||
![Drop Save Here](DropSave.png)
|
![Drop Save Here](DropSave.png)
|
||||||
![Code Field](CodeField.png)
|
|
||||||
|
#### An example:
|
||||||
|
![Example Code](ExampleCode.png)
|
||||||
|
|
||||||
|
#### Code that resulted from ```fCe\w9!iBXJ1ijn&```:
|
||||||
|
![Decoded Code](DecodedCode.png)
|
||||||
|
|
||||||
|
#### If you enter wrong code:
|
||||||
![Incorrect Code Entered](IncorrectCode.png)
|
![Incorrect Code Entered](IncorrectCode.png)
|
8
build.bat
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
@ECHO OFF
|
||||||
|
set pkg=me\theentropyshard\jdarkroom
|
||||||
|
mkdir out
|
||||||
|
javac -encoding utf8 -classpath src\%pkg% -d out -sourcepath . src\%pkg%\*.java
|
||||||
|
cd out
|
||||||
|
jar cfe0 JDarkroom.jar me.theentropyshard.jdarkroom.Main %pkg%\*.class -C ..\resources .
|
||||||
|
move JDarkroom.jar ..\
|
||||||
|
cd ..\
|
BIN
resources/background.png
Normal file
After Width: | Height: | Size: 217 KiB |
BIN
resources/mdisk.png
Normal file
After Width: | Height: | Size: 853 B |
4
resources/readme.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
background.png taken from the Internet, resized and darkened
|
||||||
|
mdisk.ico taken from https://github.com/9214/daruma, I sent an email asking for
|
||||||
|
this icon, at the moment of writing this, author still not answered, but the license is
|
||||||
|
WTFPL, so I think it is OK to take this icon.
|
2
run-en.bat
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@ECHO OFF
|
||||||
|
java -jar JDarkroom.jar en-US
|
2
run-ru.bat
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@ECHO OFF
|
||||||
|
java -jar JDarkroom.jar ru-RU
|
3
src/META-INF/MANIFEST.MF
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: me.theentropyshard.jdarkroom.Main
|
||||||
|
|
97
src/me/theentropyshard/jdarkroom/Decoder.java
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
|
public enum Decoder {
|
||||||
|
;
|
||||||
|
|
||||||
|
public static String decodeInternetCode(String code) {
|
||||||
|
byte[] bytes = new byte[16];
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
bytes[i] = DecodingData.CODE_INDEX_TABLE.get(Character.toString(code.charAt(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 6; i > 0; i--) {
|
||||||
|
int byte1 = 2 * i + i / 6;
|
||||||
|
int bi1 = i % 6;
|
||||||
|
int byte2 = 15;
|
||||||
|
int bi2 = i - 1;
|
||||||
|
|
||||||
|
Utils.swapBits(byte1, byte2, bi1, bi2, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
String bin = Integer.toBinaryString(bytes[bytes.length - 1]);
|
||||||
|
int index = Integer.parseInt(bin.substring(0, 3), 2);
|
||||||
|
|
||||||
|
byte firstRoundKey = DecodingData.KEY[index];
|
||||||
|
byte secondRoundKey = DecodingData.KEY[DecodingData.KEY.length - 1 - index];
|
||||||
|
|
||||||
|
for(int i = 30; i > 0; i--) {
|
||||||
|
int m = (i * firstRoundKey + 45) % 90;
|
||||||
|
int n = (i * secondRoundKey + 45) % 90;
|
||||||
|
int p = m % 6;
|
||||||
|
int q = n % 6;
|
||||||
|
|
||||||
|
int byte1 = (m - p) / 6;
|
||||||
|
int bi1 = p;
|
||||||
|
int byte2 = (n - q) / 6;
|
||||||
|
int bi2 = q;
|
||||||
|
|
||||||
|
Utils.swapBits(byte1, byte2, bi1, bi2, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte thirdRoundKey = DecodingData.KEY[bytes[bytes.length - 1] & 0b111];
|
||||||
|
|
||||||
|
for(int i = 40; i > 0; i--) {
|
||||||
|
int m = i * thirdRoundKey % 90;
|
||||||
|
int n = m % 6;
|
||||||
|
int byteInd = (m - n) / 6;
|
||||||
|
int bitInd = n;
|
||||||
|
|
||||||
|
bytes[byteInd] ^= (1 << bitInd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Decoder.readInternetCode(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readInternetCode(byte[] bytes) {
|
||||||
|
int intCode = 0;
|
||||||
|
intCode |= (bytes[8] & (0x1E000000 >> 25)) << 25;
|
||||||
|
intCode |= (bytes[9] & (0x01000000 >> 19)) << 19;
|
||||||
|
intCode |= (bytes[9] & (0x00001F00 >> 8)) << 8;
|
||||||
|
intCode |= (bytes[10] & (0x001F0000 >> 14)) << 14;
|
||||||
|
intCode |= (bytes[10] & (0x0000000C >> 2)) << 2;
|
||||||
|
intCode |= (bytes[11] & (0x00000003 << 4)) >> 4;
|
||||||
|
|
||||||
|
int l1 = Integer.parseInt(Integer.toHexString((intCode >> 24) & 0xFF), 10);
|
||||||
|
int d1 = Integer.parseInt(Integer.toHexString((intCode >> 16) & 0xFF), 16);
|
||||||
|
int l2 = Integer.parseInt(Integer.toHexString((intCode >> 8) & 0xFF), 16);
|
||||||
|
int d2 = Integer.parseInt(Integer.toHexString((intCode >> 0) & 0xFF), 16);
|
||||||
|
|
||||||
|
String[] letters1 = DecodingData.SAVE_INDEX_TABLE.get(l1 + 1).split("\\s");
|
||||||
|
String[] letters2 = DecodingData.SAVE_INDEX_TABLE.get(l2 + 1).split("\\s");
|
||||||
|
|
||||||
|
String russianCode = letters1[1] + d1 + letters2[1] + d2;
|
||||||
|
String englishCode = letters1[0] + d1 + letters2[0] + d2;
|
||||||
|
|
||||||
|
String russianLabel = I18N.getString("codeLabelRu");
|
||||||
|
String englishLabel = I18N.getString("codeLabelEn");
|
||||||
|
String andText = I18N.getString("andText");
|
||||||
|
return String.format("%s: %s %s %s: %s", russianLabel, russianCode, andText, englishLabel, englishCode);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,20 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package me.theentropyshard.jdarkroom;
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -68,6 +85,7 @@ public final class DecodingData {
|
||||||
*/
|
*/
|
||||||
public static final Map<String, Byte> CODE_INDEX_TABLE = Collections.unmodifiableMap(
|
public static final Map<String, Byte> CODE_INDEX_TABLE = Collections.unmodifiableMap(
|
||||||
new HashMap<String, Byte>() {{
|
new HashMap<String, Byte>() {{
|
||||||
|
// @formatter:off
|
||||||
this.put("A", (byte) 0); this.put("А", (byte) 0);
|
this.put("A", (byte) 0); this.put("А", (byte) 0);
|
||||||
this.put("B", (byte) 1); this.put("Б", (byte) 1);
|
this.put("B", (byte) 1); this.put("Б", (byte) 1);
|
||||||
this.put("C", (byte) 2); this.put("Ц", (byte) 2);
|
this.put("C", (byte) 2); this.put("Ц", (byte) 2);
|
||||||
|
@ -132,6 +150,7 @@ public final class DecodingData {
|
||||||
this.put("9", (byte) 61); // this.put("K", (byte) 10);
|
this.put("9", (byte) 61); // this.put("K", (byte) 10);
|
||||||
this.put("?", (byte) 62); // this.put("K", (byte) 10);
|
this.put("?", (byte) 62); // this.put("K", (byte) 10);
|
||||||
this.put("!", (byte) 63); // this.put("K", (byte) 10);
|
this.put("!", (byte) 63); // this.put("K", (byte) 10);
|
||||||
|
// @formatter:on
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
64
src/me/theentropyshard/jdarkroom/I18N.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public enum I18N {
|
||||||
|
;
|
||||||
|
|
||||||
|
public static final Locale LOCALE = Locale.getDefault();
|
||||||
|
public static final String LANGUAGE = I18N.LOCALE.getLanguage().toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
|
private static final Map<String, String> TRANSLATION = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
I18N.TRANSLATION.put("en.dropFileHere", "<html>Drop save file here! (slot[0-4].sav)<br>Or click to enter Internet code!</html>");
|
||||||
|
I18N.TRANSLATION.put("ru.dropFileHere", "<html>Переместите файл сохранения сюда! (slot[0-4].sav)<br>Или нажмите, чтобы ввести Интернет-код!</html>");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("en.enterCodeHere", "Enter Internet code here");
|
||||||
|
I18N.TRANSLATION.put("ru.enterCodeHere", "Введите сюда Интернет-код");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("en.submit", "Submit");
|
||||||
|
I18N.TRANSLATION.put("ru.submit", "Отправить");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("en.incorrectCodeLength", "Internet code length must be 16 chars!");
|
||||||
|
I18N.TRANSLATION.put("ru.incorrectCodeLength", "Длина Интернет-кода должна быть 16 символов!");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("en.badFile", "Bad file given!");
|
||||||
|
I18N.TRANSLATION.put("ru.badFile", "Перемещен плохой файл!");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("ru.andText", "и");
|
||||||
|
I18N.TRANSLATION.put("en.andText", "and");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("ru.codeLabelRu", "Русский код");
|
||||||
|
I18N.TRANSLATION.put("ru.codeLabelEn", "Английский код");
|
||||||
|
|
||||||
|
I18N.TRANSLATION.put("en.codeLabelRu", "Russian code");
|
||||||
|
I18N.TRANSLATION.put("en.codeLabelEn", "English code");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(String key) {
|
||||||
|
if(key.indexOf(".") == 2) {
|
||||||
|
return I18N.TRANSLATION.get(key);
|
||||||
|
}
|
||||||
|
return I18N.TRANSLATION.get(I18N.LANGUAGE + "." + key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,21 @@
|
||||||
package me.theentropyshard.jdarkroom;
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
import java.io.File;
|
package me.theentropyshard.jdarkroom;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
|
|
||||||
public class JDarkroom {
|
public class JDarkroom {
|
||||||
public JDarkroom() {
|
public JDarkroom() {
|
||||||
|
@ -14,134 +27,6 @@ public class JDarkroom {
|
||||||
new View();
|
new View();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String findInSave(File file) {
|
|
||||||
if(file == null || file.isDirectory()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder russianCode = new StringBuilder();
|
|
||||||
StringBuilder englishCode = new StringBuilder();
|
|
||||||
try(RandomAccessFile raf = new RandomAccessFile(file, "r")) {
|
|
||||||
if(raf.length() <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
raf.seek(DecodingData.CODE_OFFSET);
|
|
||||||
|
|
||||||
for(int i = 0; i < 16; i++) {
|
|
||||||
byte b = raf.readByte();
|
|
||||||
if(i % 4 == 0) {
|
|
||||||
String[] letters = DecodingData.SAVE_INDEX_TABLE.get((int) b).split("\\s");
|
|
||||||
russianCode.append(letters[1]);
|
|
||||||
englishCode.append(letters[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return russianCode + " or " + englishCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String decodeInternetCode(String code) {
|
|
||||||
if(code == null || code.length() != 16) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = new byte[16];
|
|
||||||
for(int i = 0; i < 16; i++) {
|
|
||||||
bytes[i] = DecodingData.CODE_INDEX_TABLE.get(Character.toString(code.charAt(i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 6; i > 0; i--) {
|
|
||||||
int byte1 = 2 * i + i / 6;
|
|
||||||
int bi1 = i % 6;
|
|
||||||
int byte2 = 15;
|
|
||||||
int bi2 = i - 1;
|
|
||||||
|
|
||||||
JDarkroom.swapBits(byte1, byte2, bi1, bi2, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
String bin = Integer.toBinaryString(bytes[bytes.length - 1]);
|
|
||||||
int index = Integer.parseInt(bin.substring(0, 3), 2);
|
|
||||||
|
|
||||||
byte firstRoundKey = DecodingData.KEY[index];
|
|
||||||
byte secondRoundKey = DecodingData.KEY[DecodingData.KEY.length - 1 - index];
|
|
||||||
|
|
||||||
for(int i = 30; i > 0; i--) {
|
|
||||||
int m = (i * firstRoundKey + 45) % 90;
|
|
||||||
int n = (i * secondRoundKey + 45) % 90;
|
|
||||||
int p = m % 6;
|
|
||||||
int q = n % 6;
|
|
||||||
|
|
||||||
int byte1 = (m - p) / 6;
|
|
||||||
int bi1 = p;
|
|
||||||
int byte2 = (n - q) / 6;
|
|
||||||
int bi2 = q;
|
|
||||||
|
|
||||||
JDarkroom.swapBits(byte1, byte2, bi1, bi2, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte thirdRoundKey = DecodingData.KEY[bytes[bytes.length - 1] & 0b111];
|
|
||||||
|
|
||||||
for(int i = 40; i > 0; i--) {
|
|
||||||
int m = i * thirdRoundKey % 90;
|
|
||||||
int n = m % 6;
|
|
||||||
int byteInd = (m - n) / 6;
|
|
||||||
int bitInd = n;
|
|
||||||
|
|
||||||
bytes[byteInd] ^= (1 << bitInd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int intCode = 0;
|
|
||||||
intCode |= (bytes[8] & (0x1E000000 >> 25)) << 25;
|
|
||||||
intCode |= (bytes[9] & (0x01000000 >> 19)) << 19;
|
|
||||||
intCode |= (bytes[9] & (0x00001F00 >> 8)) << 8;
|
|
||||||
intCode |= (bytes[10] & (0x001F0000 >> 14)) << 14;
|
|
||||||
intCode |= (bytes[10] & (0x0000000C >> 2)) << 2;
|
|
||||||
intCode |= (bytes[11] & (0x00000003 << 4)) >> 4;
|
|
||||||
|
|
||||||
int l1 = Integer.parseInt(Integer.toHexString((intCode >> 24) & 0xFF), 10);
|
|
||||||
int d1 = Integer.parseInt(Integer.toHexString((intCode >> 16) & 0xFF), 16);
|
|
||||||
int l2 = Integer.parseInt(Integer.toHexString((intCode >> 8) & 0xFF), 16);
|
|
||||||
int d2 = Integer.parseInt(Integer.toHexString((intCode >> 0) & 0xFF), 16);
|
|
||||||
|
|
||||||
String[] letters1 = DecodingData.SAVE_INDEX_TABLE.get(l1 + 1).split("\\s");
|
|
||||||
String[] letters2 = DecodingData.SAVE_INDEX_TABLE.get(l2 + 1).split("\\s");
|
|
||||||
|
|
||||||
String russianCode = letters1[1] + d1 + letters2[1] + d2;
|
|
||||||
String englishCode = letters1[0] + d1 + letters2[0] + d2;
|
|
||||||
|
|
||||||
return russianCode + " or " + englishCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swaps two different bits in two numbers
|
|
||||||
*
|
|
||||||
* @param byteInd1 Index of first byte
|
|
||||||
* @param byteInd2 Index of second byte
|
|
||||||
* @param bi1 0-based bit from first number, indexed from right
|
|
||||||
* @param bi2 0-based bit from second number, indexed from right
|
|
||||||
* @param bytes Byte array
|
|
||||||
*/
|
|
||||||
public static void swapBits(int byteInd1, int byteInd2, int bi1, int bi2, byte... bytes) {
|
|
||||||
int bit1 = (bytes[byteInd1] >> bi1) & 1;
|
|
||||||
int bit2 = (bytes[byteInd2] >> bi2) & 1;
|
|
||||||
|
|
||||||
if(bit1 == 0) {
|
|
||||||
bytes[byteInd2] &= ~(1 << bi2);
|
|
||||||
} else {
|
|
||||||
bytes[byteInd2] |= 1 << bi2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bit2 == 0) {
|
|
||||||
bytes[byteInd1] &= ~(1 << bi1);
|
|
||||||
} else {
|
|
||||||
bytes[byteInd1] |= 1 << bi1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JDarkroom instance;
|
private static JDarkroom instance;
|
||||||
|
|
||||||
public static JDarkroom getInstance() {
|
public static JDarkroom getInstance() {
|
||||||
|
|
|
@ -1,11 +1,47 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package me.theentropyshard.jdarkroom;
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
JDialog.setDefaultLookAndFeelDecorated(true);
|
Pattern localePattern = Pattern.compile("([a-z]{2})-([A-Z]{2})$");
|
||||||
JFrame.setDefaultLookAndFeelDecorated(true);
|
if(args.length > 0) {
|
||||||
|
Matcher matcher = localePattern.matcher(args[0]);
|
||||||
|
if(matcher.matches()) {
|
||||||
|
try {
|
||||||
|
String[] langAndCountry = args[0].split("-");
|
||||||
|
Locale.setDefault(new Locale(langAndCountry[0], langAndCountry[1]));
|
||||||
|
} catch (Exception se) {
|
||||||
|
se.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ignored) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
new JDarkroom();
|
new JDarkroom();
|
||||||
}
|
}
|
||||||
|
|
59
src/me/theentropyshard/jdarkroom/SaveFileReader.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
|
public enum SaveFileReader {
|
||||||
|
;
|
||||||
|
|
||||||
|
public static String findInSave(File file) {
|
||||||
|
if(file == null || file.isDirectory()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder russianCode = new StringBuilder();
|
||||||
|
StringBuilder englishCode = new StringBuilder();
|
||||||
|
try(RandomAccessFile raf = new RandomAccessFile(file, "r")) {
|
||||||
|
if(raf.length() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
raf.seek(DecodingData.CODE_OFFSET);
|
||||||
|
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
byte b = raf.readByte();
|
||||||
|
if(i % 4 == 0) {
|
||||||
|
String[] letters = DecodingData.SAVE_INDEX_TABLE.get((int) b).split("\\s");
|
||||||
|
russianCode.append(letters[1]);
|
||||||
|
englishCode.append(letters[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String russianLabel = I18N.getString("codeLabelRu");
|
||||||
|
String englishLabel = I18N.getString("codeLabelEn");
|
||||||
|
String andText = I18N.getString("andText");
|
||||||
|
return String.format("%s: %s %s %s: %s", russianLabel, russianCode, andText, englishLabel, englishCode);
|
||||||
|
}
|
||||||
|
}
|
73
src/me/theentropyshard/jdarkroom/Utils.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public enum Utils {
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Map<String, BufferedImage> IMAGE_CACHE = new HashMap<>();
|
||||||
|
|
||||||
|
public static BufferedImage loadImage(String path) {
|
||||||
|
if(Utils.IMAGE_CACHE.containsKey(path)) {
|
||||||
|
return Utils.IMAGE_CACHE.get(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedImage bufferedImage = ImageIO.read(Objects.requireNonNull(Utils.class.getResourceAsStream(path)));
|
||||||
|
Utils.IMAGE_CACHE.put(path, bufferedImage);
|
||||||
|
return bufferedImage;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps two different bits in two numbers
|
||||||
|
*
|
||||||
|
* @param byteInd1 Index of first byte
|
||||||
|
* @param byteInd2 Index of second byte
|
||||||
|
* @param bi1 0-based bit from first number, indexed from right
|
||||||
|
* @param bi2 0-based bit from second number, indexed from right
|
||||||
|
* @param bytes Byte array
|
||||||
|
*/
|
||||||
|
public static void swapBits(int byteInd1, int byteInd2, int bi1, int bi2, byte... bytes) {
|
||||||
|
int bit1 = (bytes[byteInd1] >> bi1) & 1;
|
||||||
|
int bit2 = (bytes[byteInd2] >> bi2) & 1;
|
||||||
|
|
||||||
|
if(bit1 == 0) {
|
||||||
|
bytes[byteInd2] &= ~(1 << bi2);
|
||||||
|
} else {
|
||||||
|
bytes[byteInd2] |= 1 << bi2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bit2 == 0) {
|
||||||
|
bytes[byteInd1] &= ~(1 << bi1);
|
||||||
|
} else {
|
||||||
|
bytes[byteInd1] |= 1 << bi1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,20 @@
|
||||||
|
/* JDarkroom. Reimplementation of Darkroom website.
|
||||||
|
* Copyright (C) 2023 TheEntropyShard
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package me.theentropyshard.jdarkroom;
|
package me.theentropyshard.jdarkroom;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -8,107 +25,215 @@ import java.awt.dnd.DropTarget;
|
||||||
import java.awt.dnd.DropTargetDropEvent;
|
import java.awt.dnd.DropTargetDropEvent;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class View extends JPanel {
|
public final class View extends JPanel {
|
||||||
private static final String YOUR_CODE_IS = "Your code is: ";
|
private static final Color TRANSPARENT_COLOR = new Color(255, 255, 255, 96);
|
||||||
private static final float FONT_SIZE = 20.0F;
|
private static final Color TRANSPARENT_COLOR_DARKER = View.TRANSPARENT_COLOR.darker().darker().darker();
|
||||||
private final JTextField codeField;
|
private static final BufferedImage BACKGROUND = Utils.loadImage("/background.png");
|
||||||
|
private static final int WIDTH = View.BACKGROUND.getWidth();
|
||||||
|
private static final int HEIGHT = View.BACKGROUND.getHeight();
|
||||||
|
private static final Font FONT = new Font("Arial", Font.BOLD, 14);
|
||||||
|
|
||||||
|
private final JLabel resultLabel;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public View() {
|
public View() {
|
||||||
this.setPreferredSize(new Dimension(800, 600));
|
this.setPreferredSize(new Dimension(View.WIDTH, View.HEIGHT));
|
||||||
|
|
||||||
CardLayout cardLayout = new CardLayout();
|
CardLayout cardLayout = new CardLayout(30, 50);
|
||||||
this.setLayout(cardLayout);
|
this.setLayout(cardLayout);
|
||||||
|
|
||||||
JLabel codeLabel = new JLabel(View.YOUR_CODE_IS) {{
|
this.resultLabel = new JLabel() {{
|
||||||
this.setHorizontalAlignment(JLabel.CENTER);
|
this.setHorizontalAlignment(JLabel.CENTER);
|
||||||
this.setFont(this.getFont().deriveFont(View.FONT_SIZE));
|
this.setFont(View.FONT);
|
||||||
this.setFocusable(true);
|
|
||||||
this.addMouseListener(new MouseAdapter() {
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
super.mouseClicked(e);
|
|
||||||
cardLayout.show(View.this, "DropLabel");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}};
|
}};
|
||||||
this.add(codeLabel, "CodeLabel");
|
|
||||||
|
|
||||||
JLabel dropLabel = new JLabel("Drop save file here, or click to enter Internet Code!", JLabel.CENTER) {{
|
JPanel dropFilePanel = new JPanel() {
|
||||||
this.setDropTarget(new DropTarget() {
|
{
|
||||||
@Override
|
this.setOpaque(false);
|
||||||
public synchronized void drop(DropTargetDropEvent e) {
|
this.setLayout(new GridBagLayout());
|
||||||
try {
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
e.acceptDrop(DnDConstants.ACTION_COPY);
|
c.fill = GridBagConstraints.BOTH;
|
||||||
List<File> droppedFiles = (List<File>) e.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
|
c.anchor = GridBagConstraints.CENTER;
|
||||||
String code = JDarkroom.getInstance().findInSave(droppedFiles.get(0));
|
this.addMouseListener(new MouseAdapter() {
|
||||||
if(code == null) {
|
@Override
|
||||||
codeLabel.setText("Incorrect Internet Code entered!");
|
public void mousePressed(MouseEvent e) {
|
||||||
codeLabel.setForeground(Color.RED);
|
super.mousePressed(e);
|
||||||
codeField.setText("");
|
cardLayout.show(View.this, "enterCodePanel");
|
||||||
} else {
|
}
|
||||||
codeLabel.setForeground(Color.DARK_GRAY);
|
});
|
||||||
codeLabel.setText(View.YOUR_CODE_IS + code);
|
this.add(new JPanel() {
|
||||||
}
|
{
|
||||||
cardLayout.show(View.this, "CodeLabel");
|
this.setOpaque(false);
|
||||||
e.dropComplete(true);
|
this.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
|
||||||
} catch (Exception ex) {
|
this.add(new JLabel(I18N.getString("dropFileHere")) {{
|
||||||
ex.printStackTrace();
|
this.setFont(View.FONT);
|
||||||
|
this.setHorizontalAlignment(JLabel.CENTER);
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
this.addMouseListener(new MouseAdapter() {
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
super.mouseClicked(e);
|
|
||||||
cardLayout.show(View.this, "InputPanel");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.setFocusable(true);
|
|
||||||
this.setFont(this.getFont().deriveFont(View.FONT_SIZE));
|
|
||||||
}};
|
|
||||||
this.add(dropLabel, "DropLabel");
|
|
||||||
|
|
||||||
JPanel panel = new JPanel(new GridBagLayout());
|
@Override
|
||||||
GridBagConstraints c = new GridBagConstraints();
|
protected void paintComponent(Graphics g) {
|
||||||
c.fill = GridBagConstraints.BOTH;
|
super.paintComponent(g);
|
||||||
c.anchor = GridBagConstraints.CENTER;
|
g.setColor(View.TRANSPARENT_COLOR_DARKER);
|
||||||
|
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||||
|
}
|
||||||
|
}, c);
|
||||||
|
this.setDropTarget(new DropTarget() {
|
||||||
|
@Override
|
||||||
|
public synchronized void drop(DropTargetDropEvent dtde) {
|
||||||
|
dtde.acceptDrop(DnDConstants.ACTION_COPY);
|
||||||
|
try {
|
||||||
|
List<File> droppedFiles = (List<File>)
|
||||||
|
dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
|
||||||
|
String code = SaveFileReader.findInSave(droppedFiles.get(0));
|
||||||
|
if(code == null) {
|
||||||
|
resultLabel.setText(I18N.getString("badFile"));
|
||||||
|
} else {
|
||||||
|
resultLabel.setText(code);
|
||||||
|
}
|
||||||
|
cardLayout.show(View.this, "resultPanel");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
dtde.dropComplete(false);
|
||||||
|
}
|
||||||
|
dtde.dropComplete(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.codeField = new JTextField() {{
|
@Override
|
||||||
this.setPreferredSize(new Dimension(250, 50));
|
protected void paintComponent(Graphics g) {
|
||||||
this.setFont(this.getFont().deriveFont(View.FONT_SIZE));
|
super.paintComponent(g);
|
||||||
}};
|
g.setColor(View.TRANSPARENT_COLOR);
|
||||||
panel.add(this.codeField, c);
|
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
JButton button = new JButton("Enter") {{
|
JPanel enterCodePanel = new JPanel() {
|
||||||
this.setPreferredSize(new Dimension(100, 50));
|
{
|
||||||
this.setFont(this.getFont().deriveFont(View.FONT_SIZE));
|
this.setOpaque(false);
|
||||||
this.addActionListener(e -> {
|
this.setLayout(new BorderLayout());
|
||||||
String code = JDarkroom.getInstance().decodeInternetCode(codeField.getText());
|
this.add(new JPanel() {{
|
||||||
if(code == null) {
|
this.setOpaque(false);
|
||||||
codeLabel.setText("Incorrect Internet Code entered!");
|
this.setLayout(new GridBagLayout());
|
||||||
codeLabel.setForeground(Color.RED);
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
codeField.setText("");
|
c.fill = GridBagConstraints.BOTH;
|
||||||
} else {
|
c.anchor = GridBagConstraints.CENTER;
|
||||||
codeLabel.setForeground(Color.DARK_GRAY);
|
JTextField textField = new JTextField() {{
|
||||||
codeLabel.setText(View.YOUR_CODE_IS + code);
|
this.setFont(View.FONT);
|
||||||
}
|
this.setPreferredSize(new Dimension(220, 30));
|
||||||
cardLayout.show(View.this, "CodeLabel");
|
}};
|
||||||
});
|
this.add(new JPanel() {
|
||||||
}};
|
{
|
||||||
|
this.setOpaque(false);
|
||||||
|
this.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
|
||||||
|
this.setLayout(new GridLayout(2, 1));
|
||||||
|
this.add(new JPanel() {{
|
||||||
|
this.setLayout(new BorderLayout());
|
||||||
|
this.setOpaque(false);
|
||||||
|
this.add(new JLabel(I18N.getString("enterCodeHere")) {{
|
||||||
|
this.setHorizontalAlignment(JLabel.CENTER);
|
||||||
|
this.setFont(View.FONT);
|
||||||
|
}});
|
||||||
|
}});
|
||||||
|
this.add(new JPanel() {{
|
||||||
|
this.setOpaque(false);
|
||||||
|
this.add(textField);
|
||||||
|
this.add(new JButton(I18N.getString("submit")) {{
|
||||||
|
this.setFont(View.FONT);
|
||||||
|
this.setPreferredSize(new Dimension(120, 30));
|
||||||
|
this.addActionListener(e -> {
|
||||||
|
String text = textField.getText();
|
||||||
|
textField.setText("");
|
||||||
|
if(text.length() != 16) {
|
||||||
|
resultLabel.setText(I18N.getString("incorrectCodeLength"));
|
||||||
|
} else {
|
||||||
|
resultLabel.setText(Decoder.decodeInternetCode(text));
|
||||||
|
}
|
||||||
|
cardLayout.show(View.this, "resultPanel");
|
||||||
|
});
|
||||||
|
}});
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
panel.add(button, c);
|
@Override
|
||||||
this.add(panel, "InputPanel");
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.setColor(View.TRANSPARENT_COLOR_DARKER);
|
||||||
|
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||||
|
}
|
||||||
|
}, c);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
cardLayout.show(this, "DropLabel");
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.setColor(View.TRANSPARENT_COLOR);
|
||||||
|
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JPanel resultPanel = new JPanel() {
|
||||||
|
{
|
||||||
|
this.setOpaque(false);
|
||||||
|
this.setLayout(new GridBagLayout());
|
||||||
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
|
c.fill = GridBagConstraints.BOTH;
|
||||||
|
c.anchor = GridBagConstraints.CENTER;
|
||||||
|
this.add(new JPanel() {
|
||||||
|
{
|
||||||
|
this.setOpaque(false);
|
||||||
|
this.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
|
||||||
|
this.add(resultLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.setColor(View.TRANSPARENT_COLOR_DARKER);
|
||||||
|
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||||
|
}
|
||||||
|
}, c);
|
||||||
|
this.addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
super.mousePressed(e);
|
||||||
|
cardLayout.show(View.this, "dropFilePanel");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.setColor(View.TRANSPARENT_COLOR);
|
||||||
|
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.add(dropFilePanel, "dropFilePanel");
|
||||||
|
this.add(enterCodePanel, "enterCodePanel");
|
||||||
|
this.add(resultPanel, "resultPanel");
|
||||||
|
|
||||||
|
cardLayout.show(this, "dropFilePanel");
|
||||||
|
|
||||||
JFrame frame = new JFrame("JDarkroom");
|
JFrame frame = new JFrame("JDarkroom");
|
||||||
frame.add(this);
|
frame.add(this, BorderLayout.CENTER);
|
||||||
frame.pack();
|
frame.pack();
|
||||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||||
|
frame.setIconImage(Utils.loadImage("/mdisk.png"));
|
||||||
frame.setLocationRelativeTo(null);
|
frame.setLocationRelativeTo(null);
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.drawImage(View.BACKGROUND, 0, 0, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|