NeoLayoutViewer/neo2.vala

436 lines
12 KiB
Vala

using Gtk;
using Gdk;
using X; //keysym.h
using Posix;//system-calls
namespace NeoLayoutViewer{
public class NeoWindow : Gtk.Window {
private Gtk.Image image;
public Gtk.Label status;
private Gdk.Pixbuf[] image_buffer;
public Gee.HashMap<string, string> config;
public int ebene;
public int[] active_modifier;
public int numblock_width;
//private Button button;
private bool minimized;
private int position_num;
private int[] position_cycle;
/* Die Neo-Modifier unterscheiden sich zum Teil von den Normalen, für die Konstanten definiert sind. Bei der Initialisierung werden aus den Standardkonstanen die Konstenen für die Ebenen 1-6 berechnet.*/
public int[] NEO_MODIFIER_MASK;
public int[] MODIFIER_MASK;
// /* Modifier-codes für CTLR, ALT, ... */
// public int[] OTHER_MODIFIER_MASK;
/* Die Keycodes von ShiftL, ShiftR, Mod3 (Alt Gr,<) und Mod4 (CapsLock, #)... in der Uni schon mal keine Übereinstimmung*/
//private int[] MODIFIER_KEY_CODES = {65505,65506,65027,65041};//home
//private int[] MODIFIER_KEY_CODES = {65505,65506,65406,65027};//uni
/* Falls ein Modifier (oder eine andere Taste) gedrückt wird und schon Modifier gedrückt sind, gibt die Map an, welche Ebene dann aktiviert ist. */
private short[,] MODIFIER_MAP = {
{0,1,2,3,4,5},
{1,1,4,3,4,5},
{2,4,2,5,4,5},
{3,3,5,3,4,5} };
/* [0,1]^3->{0,5}, Bildet aktive Modifier auf angezeigte Ebene ab.
Interpretationsreihenfolge der Dimensionen: Shift,Neo-Mod3, Neo-Mod4. */
private short[,,] MODIFIER_MAP2 = {
{ {0 , 3}, {2 , 5 } }, // 000, 001; 010, 011
{ {1 , 3}, {4 , 5}} // 100, 101; 110, 111
};
/* Analog zu oben für den Fall, dass eine Taste losgelassen wird. Funktioniert nicht immer.
Ist beispielsweise ShiftL und ShiftR gedrückt und eine wird losgelassen, so wechelt die Anzeige zur ersten Ebene.
Die Fehler sind imo zu vernachlässigen.
*/
private short[,] MODIFIER_MAP_RELEASE = {
{0,0,0,0,0,0},
{0,0,2,3,2,5},
{0,1,0,3,1,3},
{0,1,2,0,4,2} };
public NeoWindow (string sebene, Gee.HashMap<string, string> config) {
this.config = config;
this.minimized = true;
this.NEO_MODIFIER_MASK = {
0,
Gdk.ModifierType.SHIFT_MASK, //1
Gdk.ModifierType.MOD5_MASK+Gdk.ModifierType.LOCK_MASK, //128+2
Gdk.ModifierType.MOD3_MASK, //32
Gdk.ModifierType.MOD5_MASK+Gdk.ModifierType.LOCK_MASK+Gdk.ModifierType.SHIFT_MASK, //128+2+1
Gdk.ModifierType.MOD5_MASK+Gdk.ModifierType.LOCK_MASK+Gdk.ModifierType.MOD3_MASK //128+2+32
};
/*
this.OTHER_MODIFIER_MASK = {
Gdk.ModifierType.CONTROL_MASK,
Gdk.ModifierType.MOD1_MASK
};*/
this.MODIFIER_MASK = {
0,
Gdk.ModifierType.SHIFT_MASK, //1
Gdk.ModifierType.MOD5_MASK,//128
Gdk.ModifierType.MOD3_MASK, //32
Gdk.ModifierType.CONTROL_MASK,
Gdk.ModifierType.MOD1_MASK // Alt-Mask do not work :-(
};
this.active_modifier = {0,0,0,0,0,0};
this.position_num = int.max(int.min(int.parse(config.get("position")),9),1);
//Anlegen des Arrays, welches den Positionsdurchlauf beschreibt.
try{
var space = new Regex(" ");
string[] split = space.split(config.get("position_cycle"));
position_cycle = new int[int.max(9,split.length)];
for(int i=0;i<split.length;i++){
position_cycle[i] = int.max(int.min(int.parse(split[i]),9),1);//Zulässiger Bereich: 1-9
}
} catch (RegexError e) {
position_cycle = {3,3,9,1,3,9,1,7,7};
}
this.ebene = int.parse(sebene);
if(this.ebene<1 || this.ebene>6) {this.ebene = 1; }
//Lade die Pngs der sechs Ebenen
this.load_image_buffer();
this.image = new Gtk.Image();//.from_pixbuf(this.image_buffer[ebene]);
// Create an image and render first page to image
//var pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, 800, 600);
render_page ();
var fixed = new Fixed();
add(fixed);
fixed.put(this.image, 0, 0);
fixed.put( new KeyOverlay(this) , 0, 0);
this.status = new Label("");
fixed.put( status, 2, 2 );
//Fenstereigenschaften setzen
this.key_press_event.connect (on_key_pressed);
this.destroy.connect (Gtk.main_quit);
this.set_gravity(Gdk.Gravity.SOUTH);
//this.move(-100,-100);
/*GdkGeometry size_hints = {
100, 50, 0, 0, 100, 50, 10, 10, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
};
gtk_window_set_geometry_hints (GTK_WINDOW (this), this, &size_hints,
GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC);
*/
//this.window_position = WindowPosition.CENTER;
//this.default_height = int.parse( config.get("height") );
//this.default_width = int.parse( config.get("width") );
this.decorated = false;
//this.allow_grow = false;
//this.allow_shrink = false;
this.skip_taskbar_hint = true;
this.show_all();
//Move ist erst nach show_all() erfolgreich
this.numkeypad_move(int.parse(config.get("position")));
//Icon des Fensters
this.icon = this.image_buffer[0];
//Nicht selektierbar (für virtuelle Tastatur)
this.set_accept_focus(false);
}
public override void show_all(){
this.minimized = false;
base.show_all();
//this.present();
//set_visible(true);
this.numkeypad_move(this.position_num);
if( config.get("on_top")=="1")
this.set_keep_above(true);
else
this.present();
}
public override void hide_all(){
this.minimized = true;
base.hide_all();
//set_visible(false);
}
public bool toggle(){
if(this.minimized) show_all();
else hide_all();
return this.minimized;
}
/* Falsche Werte bei „Tiled Window Managern“. */
public void get_size2(out int width, out int height){
width = this.image_buffer[1].width;
height = this.image_buffer[1].height;
}
public void numkeypad_move(int pos){
int screen_width = this.screen.width();
int screen_height = this.screen.height();
int x,y,w,h;
this.get_size(out w,out h);
switch (pos){
case 0: //Zur nächsten Position wechseln
numkeypad_move(this.position_cycle[this.position_num-1]);
return;
case 7:
x = 0;
y = 0;
break;
case 8:
x = (screen_width-w)/2;
y = 0;
break;
case 9:
x = screen_width-w;
y = 0;
break;
case 4:
x = 0;
y = (screen_height-h)/2;
break;
case 5:
x = (screen_width-w)/2;
y = (screen_height-h)/2;
break;
case 6:
x = screen_width-w;
y = (screen_height-h)/2;
break;
case 1:
x = 0;
y = screen_height-h;
break;
case 2:
x = (screen_width-w)/2;
y = screen_height-h;
break;
//case 3: //=default case
// ;
default:
x = screen_width-w;
y = screen_height-h;
break;
}
this.position_num = pos;
this.move(x,y);
}
public Gdk.Pixbuf open_image (int ebene) {
var bildpfad = "assets/neo2.1/tastatur_neo_Ebene%i.png".printf(ebene);
return open_image_str(bildpfad);
//return new Image_from_pixpuf(open_image_str(bildpfad));
}
public Gdk.Pixbuf open_image_str (string bildpfad) {
try {
return new Gdk.Pixbuf.from_file (bildpfad);
} catch (Error e) {
error ("%s", e.message);
}
}
public void load_image_buffer () {
this.image_buffer = new Gdk.Pixbuf[7];
this.image_buffer[0] = open_image_str("assets/icons/Neo-Icon.png");
int screen_width = this.screen.width();
//int screen_height = this.screen.height();
int max_width = (int) ( double.parse( this.config.get("max_width") )*screen_width );
int min_width = (int) ( double.parse( this.config.get("min_width") )*screen_width );
int width = int.min(int.max(int.parse( config.get("width") ),min_width),max_width);
int w,h;
for (int i=1; i<7; i++){
this.image_buffer[i] = open_image(i);
//Numpad-Teil abschneiden, falls gefordert
this.numblock_width = int.parse(config.get("numblock_width"));
if( config.get("display_numblock")=="0" ){
var tmp = new Gdk.Pixbuf(image_buffer[i].colorspace,image_buffer[i].has_alpha,image_buffer[i].bits_per_sample, image_buffer[i].width-numblock_width ,image_buffer[i].height);
this.image_buffer[i].copy_area(0,0,tmp.width,tmp.height,tmp,0,0);
this.image_buffer[i] = tmp;
}
//Bilder einmaling beim Laden skalieren. (Keine spätere Skalierung durch Größenänderung des Fensters)
w = this.image_buffer[i].width;
h = this.image_buffer[i].height;
this.image_buffer[i] = this.image_buffer[i].scale_simple(width, h*width/w,Gdk.InterpType.BILINEAR);
}
}
private bool on_key_pressed (Widget source, Gdk.EventKey key) {
// If the key pressed was q, quit, else show the next page
if (key.str == "q") {
Gtk.main_quit ();
}
if (key.str == "h") {
this.hide_all();
}
/* Erste Auswahlvariante: Zahlen 1-6 */
var ebene_tmp = int.parse(key.str);
if(ebene_tmp>0 && ebene_tmp<7) {
if(this.ebene != ebene_tmp){
this.ebene = ebene_tmp;
render_page ();
}
}
/*else{
//Finde die aktuelle Taste und die derzeit gedrückten Modifier
int iet1 = 0;
int iet2 = 0;
debug("%u".printf(key.keyval));
if( key.keyval == MODIFIER_KEY_CODES[0] || key.keyval == MODIFIER_KEY_CODES[1]){
iet1=1;
}else if( key.keyval == MODIFIER_KEY_CODES[2]){
iet1=2;
}else if( key.keyval == MODIFIER_KEY_CODES[3]){
iet1=3;
}
for(int i=0; i<6; i++){
if( key.state == NEO_MODIFIER_MASK[i]){
iet2=i;
break;
}
}
iet1 = this.MODIFIER_MAP[iet1,iet2]+1;
check_modifier(iet1);
}*/
/*
stdout.printf("Aktuell: %i \nModifierids: %i %i %i %i\n %i %i %i %i \n %i %i %i %i %i\n\n",
key.state, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.LOCK_MASK, Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK, Gdk.ModifierType.META_MASK, Gdk.ModifierType.RELEASE_MASK, Gdk.ModifierType.MODIFIER_MASK, Gdk.ModifierType.MOD1_MASK, Gdk.ModifierType.MOD2_MASK, Gdk.ModifierType.MOD3_MASK, Gdk.ModifierType.MOD4_MASK, Gdk.ModifierType.MOD5_MASK);*/
return false;
}
private void check_modifier(int iet1){
if(iet1 != this.ebene){
this.ebene = iet1;
render_page ();
}
}
public void redraw(){
this.ebene = this.MODIFIER_MAP2[
this.active_modifier[1], //shift
this.active_modifier[2], //neo-mod3
this.active_modifier[3] //neo-mod4
] + 1;
render_page();
}
private void render_page () {
this.image.set_from_pixbuf(this.image_buffer[this.ebene]);
}
public Gdk.Pixbuf getIcon(){
return this.image_buffer[0];
}
public void external_key_press(int iet1, int modifier_mask){
for(int iet2=0; iet2<4; iet2++){
if(this.NEO_MODIFIER_MASK[iet2]==modifier_mask){
//debug("(Press) e1=%i, e2=%i\n".printf(iet1,iet2));
iet1 = this.MODIFIER_MAP[iet1,iet2]+1;
this.check_modifier(iet1);
return;
}
}
iet1 = this.MODIFIER_MAP[iet1,0]+1;
this.check_modifier(iet1);
}
public void external_key_release(int iet1, int modifier_mask){
for(int iet2=0; iet2<4; iet2++){
if(this.NEO_MODIFIER_MASK[iet2]==modifier_mask){
//debug("(Relase) e1=%i, e2=%i\n\n".printf(iet1,iet2));
iet1 = this.MODIFIER_MAP_RELEASE[iet1,iet2]+1;
this.check_modifier(iet1);
return;
}
}
iet1 = this.MODIFIER_MAP_RELEASE[iet1,0]+1;
this.check_modifier(iet1);
}
/*public void updateLayer(int iet){
if( 0<iet && iet<7 && this.ebene==iet){
this.ebene = iet;
render_page();
}
}*/
public static int main (string[] args) {
string sebene;
if( args.length<2) {
sebene="1";
}else{
sebene=args[1];
}
Gtk.init (ref args);
var configm = new ConfigManager("neolayoutviewer.conf");
var neo_win = new NeoWindow (sebene, configm.getConfig());
var neo_tray = new AppStatusIcon(neo_win);
var manager = new KeybindingManager(neo_win);
manager.bind2(50, "ShiftL",1, ()=>{});
manager.bind2(62, "ShiftR",1, ()=>{});
manager.bind2(66, "Mod3L",2, ()=>{});
manager.bind2(51, "Mod3R",2, ()=>{});
manager.bind2(94, "Mod4",3, ()=>{});
manager.bind2(108, "Mod4",3, ()=>{});
manager.bind(configm.getConfig().get("show_shortcut"), ()=>{neo_win.toggle();});
manager.bind(configm.getConfig().get("move_shortcut"), ()=>{neo_win.numkeypad_move(0);});
//neo_win.show_all ();
//neo_win.hide_all();
//move window (Fehlerquelle: config von configm, nicht neo_win. Derzeit gleiches Objekt.)
Gtk.main ();
manager.unbind2(50);
manager.unbind2(62);
manager.unbind2(66);
manager.unbind2(51);
manager.unbind2(94);
manager.unbind2(108);
return 0;
}
} //End class NeoWindow
}