diff --git a/CMakeLists.txt b/CMakeLists.txt index fa0b7bd..70e02c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,9 @@ add_executable(yellownotes main.cpp gtkloader.h gtkloader.cpp gtk-imports.c yellownotes.h yellownotes.cpp - tr.h tr.cpp) + tr.h tr.cpp + utils/whereami.c utils/whereami.h + exe_path.h exe_path.cpp) include(GNUInstallDirs) install(TARGETS yellownotes diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f64453d --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ + + +all: release + @echo make install + +install: release + mkdir -p /opt/yellownotes + cp build/release/yellownotes *.svg *.png /opt/yellownotes + +release: build/release/yellownotes + +build/release/yellownotes: exe_path.cpp gtk-imports.c gtkloader.cpp main.cpp tr.cpp yellownotes.cpp utils/whereami.c \ + exe_path.h gtk-imports.h gtkloader.h tr.h yellownotes.h utils/whereami.h + cmake -S . -B build/release + cmake --build build/release --target all + + +clean: + rm -rf build/release diff --git a/gtk-imports.h b/gtk-imports.h index 0282eb8..42b686e 100644 --- a/gtk-imports.h +++ b/gtk-imports.h @@ -1,6 +1,8 @@ #ifndef GTK_IMPORTS_H #define GTK_IMPORTS_H +#include + /************************************************************************************* * boiler plate code to initialize Gtk functions etc. *************************************************************************************/ @@ -68,13 +70,16 @@ typedef void GtkDialog; typedef void GTimer; typedef void GtkComboBoxText; typedef void GtkComboBox; +typedef void GtkGrid; +typedef void GtkColorButton; +typedef void GtkColorChooser; typedef int gboolean; typedef int gint; typedef char gchar; typedef long glong; typedef unsigned long gulong; -typedef unsigned long guint32; +typedef unsigned int guint32; typedef unsigned int guint; typedef long long gint64; typedef unsigned long long guint64; @@ -274,7 +279,7 @@ typedef struct _GdkEventMotion gint16 is_hint; GdkDevice *device; gdouble x_root, y_root; -} GdkEventMotion; +} GdkEventMotion;; typedef struct _GdkEventKey { @@ -649,11 +654,20 @@ DECL(void, gtk_widget_set_vexpand, (GtkWidget* widget, gboolean expand )) DECL(void, gtk_widget_set_hexpand, (GtkWidget* widget, gboolean expand )) DECL(void, gtk_widget_set_halign, (GtkWidget* widget, GtkAlign align )) DECL(void, gtk_widget_set_valign, (GtkWidget* widget, GtkAlign align )) +DECL(GtkWidget*,gtk_grid_new, (void)) +DECL(void, gtk_grid_attach, (GtkGrid* grid, GtkWidget* child, gint left, gint top, gint width, gint height )) + +DECL(GtkWidget*, gtk_color_button_new, (void )) +DECL(void, gtk_color_chooser_set_rgba, (GtkColorChooser* chooser, const GdkRGBA* color )) +DECL(void, gtk_color_chooser_get_rgba, (GtkColorChooser* chooser, GdkRGBA* color )) DECL(gboolean, gtk_widget_translate_coordinates, ( GtkWidget* src_widget, GtkWidget* dest_widget, gint src_x, gint src_y, gint* dest_x, gint* dest_y)) DECL(void, gtk_main, (void)) DECL(void, gtk_main_quit, (void)) +DECL(GdkEvent*, gtk_get_current_event, (void )) +DECL(void, gtk_main_do_event, (GdkEvent* event)) +DECL(void, gdk_event_free, (GdkEvent* event)) DECL(unsigned long, g_signal_connect_data, (GObject *obj, const char *signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags)) diff --git a/gtkloader.cpp b/gtkloader.cpp index 21edad6..6685ef7 100644 --- a/gtkloader.cpp +++ b/gtkloader.cpp @@ -123,6 +123,7 @@ void GtkLoader::dlopen() "libgio-2.0.so", "libglib-2.0.so", "libgdk-3.so", + "libgdk_pixbuf-2.0.so", NULL }; int i; diff --git a/main.cpp b/main.cpp index 9e88434..e9906c9 100644 --- a/main.cpp +++ b/main.cpp @@ -6,6 +6,7 @@ extern "C" { } #include "yellownotes.h" +#include "exe_path.h" SIGNAL(YellowNotes, on_tray_activate, popupTrayMenu) @@ -22,9 +23,12 @@ static void activate (GtkApplication* app, gpointer user_data) int main(int argc, char **argv) { GtkLoader l; + WhereAmI w; srand(time(NULL)); // seed with current time + std::string my_path = w.containing_folder(); + try { l.loadGtk(); } catch(std::string msg) { diff --git a/to_desktop.png b/to_desktop.png new file mode 100644 index 0000000..35b5a1e Binary files /dev/null and b/to_desktop.png differ diff --git a/to_desktop.svg b/to_desktop.svg new file mode 100644 index 0000000..c65ee3c --- /dev/null +++ b/to_desktop.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/yellownotes.cpp b/yellownotes.cpp index e055c33..f83721c 100644 --- a/yellownotes.cpp +++ b/yellownotes.cpp @@ -22,6 +22,8 @@ extern "C" { #include "tr.h" +#include + static void trim(std::string &s) { size_t start = s.find_first_not_of(" \t\n\r"); size_t end = s.find_last_not_of(" \t\n\r"); @@ -49,6 +51,7 @@ private: GtkImage *_delete_image; GtkImage *_plus_image; GtkImage *_hide_image; + GtkImage *_to_desktop_image; GtkWidget *_title_label; GtkWidget *_title_entry; GtkWidget *_title_separator; @@ -62,16 +65,24 @@ private: std::string _title; bool _hidden; + bool _hidden_loaded; + int _x; int _y; + bool _pos_loaded; + int _width; int _height; + bool _size_loaded; + bool _in_transaction; bool _editing_title; int _save_counter; int _save_id; + bool _double_clicked; + ColorType_t _color; bool _color_changed; @@ -106,11 +117,14 @@ private: void updateWidgetColors(GtkWidget *w); public: - void changed(GtkWidget *sender); - void size_allocated(GtkWidget *sender, GtkAllocation *a); + void resized(int width, int height); + void size_allocated(GtkWidget *sender, GtkAllocation *alloc); + void positioned(GtkWidget *sender, int x, int y); public: void toFront(); + void toDesktop(); + void fromDesktop(); public: bool move_begin(GtkWidget *sender, GdkEventButton *evt); @@ -127,6 +141,7 @@ public: public: std::string title(); bool isHidden(); + void doubleClicked(); public: void load(); @@ -137,6 +152,34 @@ public: ~YellowNote(); }; +class ColorSet +{ +public: + ColorType_t color; + YellowNotes *notes; + bool bg; + +public: + void colorSet(GtkColorButton *sender) { + GdkRGBA rgba; + gtk_color_chooser_get_rgba(sender, &rgba); + std::string c = notes->fromRGBA(rgba); + if (bg) { + notes->setBgColor(color, c); + } else { + notes->setFgColor(color, c); + } + } + + ColorSet(ColorType_t t, bool _bg, YellowNotes *n) { + color = t; + bg = _bg; + notes = n; + } +}; + +SIGNAL(ColorSet, on_color_set, colorSet); + SIGNAL2(YellowNote, on_size_allocated, size_allocated, GtkAllocation) BSIGNAL2(YellowNote, on_button_press, move_begin, GdkEventButton); BSIGNAL2(YellowNote, on_button_release, move_end, GdkEventButton); @@ -156,7 +199,8 @@ static gboolean on_text_save_timeout(gpointer data) } SIGNAL(YellowNotes, on_new_yellow, newNote) -SIGNAL(YellowNotes, on_show, showNotes); +SIGNAL(YellowNotes, on_show, notesFromDesktop); +SIGNAL(YellowNotes, on_to_back, notesToDesktop); SIGNAL(YellowNotes, on_reload, reloadNotes); SIGNAL(YellowNotes, on_setup, setup); SIGNAL(YellowNotes, on_quit, quit) @@ -210,28 +254,108 @@ std::string YellowNotes::notesDir() return notes_dir; } -std::string YellowNotes::css(ColorType_t type) +std::string YellowNotes::fromRGBA(const GdkRGBA &rgba) { - const char *bgs[] = { "#404040", // dark - "#faf32a", // yellow - "#fcbf56", // orange, - "#5df0f5", // blue - "#fc77f4", // Cyaan - "#74fc94", // greeen - "#f7bcbc", // red - "#cdcfd1" // grey + char buf[100]; + + auto to255 = [](double c) { + return static_cast(floor((c * 255) + 0.5)); }; - const char *fgs[] = { "white", - "black", - "black", - "black", - "black", - "black", - "black", - "black" + sprintf(buf, "#%02x%02x%02x", to255(rgba.red), to255(rgba.green), to255(rgba.blue)); + std::string col = buf; + return col; +} + +void YellowNotes::toRGBA(const std::string &col, GdkRGBA &rgba) +{ + auto from_hex = [](std::string hex_num) { + return strtol(hex_num.c_str(), NULL, 16); }; + double red = from_hex(col.substr(1, 2)) / 255.0; + double green = from_hex(col.substr(3, 2)) / 255.0; + double blue = from_hex(col.substr(5, 2)) / 255.0; + double alpha = 1.0; + + rgba.alpha = alpha; + rgba.blue = blue; + rgba.green = green; + rgba.red = red; +} + +std::string YellowNotes::getFgColor(ColorType_t type) +{ + char buf[100]; + sprintf(buf, "fg_color_%d", type); + std::string key = buf; + std::unordered_map::iterator it = _cfg.find(key); + if (it != _cfg.end()) { + return _cfg[key]; + } else { + const char *fgs[] = { "#ffffff", + "#000000", + "#000000", + "#000000", + "#000000", + "#000000", + "#000000", + "#000000" + }; + std::string c(fgs[type]); + return c; + } +} + +std::string YellowNotes::getBgColor(ColorType_t type) +{ + char buf[100]; + sprintf(buf, "bg_color_%d", type); + std::string key = buf; + std::unordered_map::iterator it = _cfg.find(key); + if (it != _cfg.end()) { + return _cfg[key]; + } else { + const char *bgs[] = { + "#404040", // dark + "#faf32a", // yellow + "#fcbf56", // orange, + "#5df0f5", // blue + "#fc77f4", // Cyaan + "#74fc94", // greeen + "#f7bcbc", // red + "#cdcfd1" // grey + }; + std::string c(bgs[type]); + return c; + } +} + +void YellowNotes::setFgColor(ColorType_t type, const std::string &col) +{ + char buf[100]; + sprintf(buf, "fg_color_%d", type); + std::string key = buf; + _cfg.erase(key); + _cfg.insert(std::pair(key, col)); + saveConfig(); +} + +void YellowNotes::setBgColor(ColorType_t type, const std::string &col) +{ + char buf[100]; + sprintf(buf, "bg_color_%d", type); + std::string key = buf; + _cfg.erase(key); + _cfg.insert(std::pair(key, col)); + saveConfig(); +} + +std::string YellowNotes::css(ColorType_t type) +{ + + if (type > LAST) { type = YELLOW; } + auto from_hex = [](std::string hex_num) { return strtol(hex_num.c_str(), NULL, 16); }; @@ -255,14 +379,14 @@ std::string YellowNotes::css(ColorType_t type) std::string css = std::string() + "label, box.horizontal, textview.view, textview.view text, frame, messagedialog.background {\n" - " background-color: " + bgs[type] + ";\n" - " color: " + fgs[type] + ";\n" + " background-color: " + getBgColor(type) + ";\n" + " color: " + getFgColor(type) + ";\n" " font-family: sans;\n" " font-size: " + font_size + ";\n" "}\n" "frame border {\n" " border: none;\n" - " box-shadow: 5px 5px 5px " + darker(bgs[type]) + ";\n" + " box-shadow: 5px 5px 5px " + darker(getBgColor(type)) + ";\n" " margin: 5px;\n" "}\n"; @@ -291,6 +415,7 @@ void YellowNotes::popupTrayMenu(void *sender) GtkMenuItem *new_yellow = gtk_menu_item_new_with_label(_("New Note")); GtkMenuItem *show_notes = gtk_menu_item_new_with_label(_("Show Notes")); + GtkMenuItem *notes_to_back = gtk_menu_item_new_with_label(_("Notes on desktop")); GtkMenuItem *reload_notes = gtk_menu_item_new_with_label(_("Reload Notes")); GtkWidget *sep = gtk_separator_menu_item_new(); @@ -314,6 +439,7 @@ void YellowNotes::popupTrayMenu(void *sender) gtk_menu_shell_append(tray_menu, new_yellow); gtk_menu_shell_append(tray_menu, show_notes); + gtk_menu_shell_append(tray_menu, notes_to_back); gtk_menu_shell_append(tray_menu, reload_notes); gtk_menu_shell_append(tray_menu, sep); @@ -330,6 +456,7 @@ void YellowNotes::popupTrayMenu(void *sender) g_signal_connect(new_yellow, "activate", on_new_yellow, this); g_signal_connect(show_notes, "activate", on_show, this); + g_signal_connect(notes_to_back, "activate", on_to_back, this); g_signal_connect(reload_notes, "activate", on_reload, this); g_signal_connect(setup, "activate", on_setup, this); g_signal_connect(quit, "activate", on_quit, this); @@ -393,6 +520,7 @@ void YellowNotes::loadConfig() } setLang(currentLang()); + } void YellowNotes::saveConfig() @@ -412,6 +540,13 @@ void YellowNotes::saveConfig() } } +gboolean load_notes_timeout(void *_notes) +{ + YellowNotes *notes = static_cast(_notes); + notes->notesToDesktop(nullptr); + return false; +} + void YellowNotes::loadNotes() { gtk_widget_show_all(topLevel()); @@ -437,12 +572,17 @@ void YellowNotes::loadNotes() const auto base_name = entry.path().filename().string(); if (base_name.rfind(".note") > 0) { YellowNote *note = new YellowNote(this, full_name); + //note->fromDesktop(); _notes.push_back(note); } } } gtk_widget_hide(topLevel()); + + if (cfgOnDesktop()) { + g_timeout_add(500, load_notes_timeout, this); + } } void YellowNotes::showNotes(void *sender) @@ -453,7 +593,27 @@ void YellowNotes::showNotes(void *sender) note->toFront(); it++; } +} +void YellowNotes::notesToDesktop(void *sender) +{ + std::list::const_iterator it = _notes.begin(); + while (it != _notes.end()) { + YellowNote *note = *it; + note->toDesktop(); + it++; + } + setCfgOnDesktop(true); +} + +void YellowNotes::notesFromDesktop(void *sender) +{ std::list::const_iterator it = _notes.begin(); + while (it != _notes.end()) { + YellowNote *note = *it; + note->fromDesktop(); + it++; + } + setCfgOnDesktop(false); } void YellowNotes::setupCancel(GtkWidget *sender) @@ -474,17 +634,22 @@ bool YellowNotes::setupDel(GtkWidget *sender, void *evt) void YellowNotes::setupClose(GtkWidget *sender) { if (_dlg != nullptr) { - std::cout << "hey" << std::endl; gtk_dialog_response(_dlg, GTK_RESPONSE_OK); std::string lang = std::string(gtk_combo_box_get_active_id(_langs)); - std::cout << "lang " << lang << std::endl; setCurrentLang(lang); gtk_widget_destroy(_dlg); + + std::list::iterator it; + for(it = _color_sets.begin() ; it != _color_sets.end(); it++) { + ColorSet *s = *it; + delete s; + } + _color_sets.clear(); + _dlg = nullptr; _langs = nullptr; saveConfig(); } else { - std::cout << "close button" << std::endl; } } @@ -504,13 +669,55 @@ void YellowNotes::setup(void *sender) gtk_combo_box_text_append(langs, "en", "English"); gtk_combo_box_text_append(langs, "nl", "Nederlands"); + GtkWidget *lbl_langs = gtk_label_new(_("Language:")); + gtk_widget_set_size_request(lbl_langs, 150, -1); + std::string current_lang = currentLang(); gtk_combo_box_set_active_id(langs, current_lang.c_str()); + gtk_widget_set_size_request(langs, 300, -1); - GtkWidget *hbox = gtk_box_new(GtkOrientation::GTK_ORIENTATION_HORIZONTAL, 5); + GtkGrid *grid = gtk_grid_new(); - gtk_container_add(hbox, langs); - gtk_container_add(content, hbox); + gtk_grid_attach(grid, lbl_langs, 0, 0, 1, 1); + gtk_grid_attach(grid, langs, 1, 0, 2, 1); + + GtkLabel *lbl_fg = gtk_label_new(_("Forground Color")); + GtkLabel *lbl_bg = gtk_label_new(_("Background Color")); + gtk_grid_attach(grid, lbl_fg, 1, 1, 1, 1); + gtk_grid_attach(grid, lbl_bg, 2, 1, 1, 1); + + + int i = ColorType_t::FIRST; + std::string colors[] = { _("Dark"), _("Yellow"), _("Orange"), + _("Blue"), _("Cyan"), _("Green"), _("Red"), _("Grey") }; + + int offset = 2; + + for(;i <= ColorType_t::LAST; i++) { + GtkWidget *lbl = gtk_label_new(colors[i].c_str()); + gtk_grid_attach(grid, lbl, 0, i + offset, 1, 1); + + GdkRGBA bg_rgba, fg_rgba; + std::string fg_color = getFgColor(static_cast(i)); + std::string bg_color = getBgColor(static_cast(i)); + toRGBA(fg_color, fg_rgba); + toRGBA(bg_color, bg_rgba); + + GtkColorButton *fg_btn = gtk_color_button_new(); + gtk_color_chooser_set_rgba(fg_btn, &fg_rgba); + ColorSet *fg = new ColorSet(static_cast(i), false, this); + g_signal_connect(fg_btn, "color_set", on_color_set, fg); + gtk_grid_attach(grid, fg_btn, 1, i + offset, 1, 1); + + GtkColorButton *bg_btn = gtk_color_button_new(); + gtk_color_chooser_set_rgba(bg_btn, &bg_rgba); + ColorSet *bg = new ColorSet(static_cast(i), true, this); + g_signal_connect(bg_btn, "color_set", on_color_set, bg); + gtk_grid_attach(grid, bg_btn, 2, i + offset, 1, 1); + + } + + gtk_container_add(content, grid); g_signal_connect(ok_btn, "clicked", on_setup_ok, this); g_signal_connect(dlg, "close", on_setup_close, this); @@ -527,8 +734,10 @@ void YellowNotes::reloadNotes(void *sender) delete note; it++; } + _notes.clear(); loadNotes(); + showNotes(sender); } @@ -582,6 +791,21 @@ std::string YellowNotes::currentLang() return _cfg[key]; } +bool YellowNotes::cfgOnDesktop() +{ + std::string key("on_desktop"); + return (_cfg[key] == "true") ? true : false; +} + +void YellowNotes::setCfgOnDesktop(bool y) +{ + std::string key("on_desktop"); + _cfg.erase(key); + std::string v = (y) ? "true" : "false"; + _cfg.insert(std::pair(key, v)); + saveConfig(); +} + void YellowNotes::setCurrentLang(const std::string &l) { std::string key("lang"); @@ -654,11 +878,22 @@ YellowNote::YellowNote(YellowNotes *notes, const std::string &filename) _color = ColorType_t::YELLOW; _color_changed = false; + _in_transaction = true; + _hidden_loaded = false; + _pos_loaded = false; + _size_loaded = false; + _double_clicked = false; + _note_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_can_focus(_note_widget, true); gtk_window_set_decorated(_note_widget, false); +#ifdef _WIN32 gtk_window_set_type_hint(_note_widget, GDK_WINDOW_TYPE_HINT_POPUP_MENU); gtk_window_set_transient_for(_note_widget, _notes->topLevel()); +#endif +#ifdef __linux + gtk_window_set_type_hint(_note_widget, GdkWindowTypeHint::GDK_WINDOW_TYPE_HINT_UTILITY); +#endif _scroll_widget = gtk_scrolled_window_new(nullptr, nullptr); gtk_widget_set_vexpand(_scroll_widget, true); @@ -712,14 +947,22 @@ YellowNote::YellowNote(YellowNotes *notes, const std::string &filename) width, height, nullptr ); _hide_image = gtk_image_new_from_pixbuf(hide_pixbuf); - gtk_widget_set_halign(_plus_image, GtkAlign::GTK_ALIGN_END); + gtk_widget_set_halign(_hide_image, GtkAlign::GTK_ALIGN_END); g_object_unref(hide_pixbuf); + GdkPixbuf *to_desktop_pixbuf = gdk_pixbuf_new_from_file_at_size(notes->imageFile("to_desktop").c_str(), + width, height, nullptr + ); + _to_desktop_image = gtk_image_new_from_pixbuf(to_desktop_pixbuf); + gtk_widget_set_halign(_to_desktop_image, GtkAlign::GTK_ALIGN_END); + g_object_unref(to_desktop_pixbuf); + gtk_container_add(_note_header, _color_image); gtk_container_add(_note_header, _title_label); gtk_container_add(_note_header, _plus_image); gtk_container_add(_note_header, _delete_image); gtk_container_add(_note_header, _hide_image); + gtk_container_add(_note_header, _to_desktop_image); gtk_container_add(_scroll_widget, _text_widget); @@ -733,6 +976,14 @@ YellowNote::YellowNote(YellowNotes *notes, const std::string &filename) gtk_widget_show_all(_note_widget); + /*while (!gtk_widget_is_visible(_note_widget)) { + GdkEvent *e = gtk_get_current_event(); + if (e != nullptr) { + gtk_main_do_event(e); + gdk_event_free(e); + } + }*/ + //GdkWindow *window = gdk_window_get_effective_toplevel(gtk_widget_get_window(_note_widget)); //gdk_window_set_events(window, static_cast(gdk_window_get_events(window) | GDK_VISIBILITY_NOTIFY_MASK)); //gdk_window_set_override_redirect(window, true); @@ -753,6 +1004,7 @@ YellowNote::YellowNote(YellowNotes *notes, const std::string &filename) g_object_ref(_delete_image); g_object_ref(_plus_image); g_object_ref(_hide_image); + g_object_ref(_to_desktop_image); load(); @@ -766,6 +1018,7 @@ YellowNote::~YellowNote() g_object_unref(_delete_image); g_object_unref(_plus_image); g_object_unref(_hide_image); + g_object_unref(_to_desktop_image); gtk_widget_destroy(_note_widget); _note_widget = nullptr; } @@ -854,6 +1107,7 @@ void YellowNote::updatePosition() void YellowNote::updateSize() { + std::cout << "Update size to: " << _width << ", " << _height << std::endl; gtk_window_resize(_note_widget, _width, _height); } @@ -876,63 +1130,39 @@ void YellowNote::hide() save(); } -void YellowNote::changed(GtkWidget *sender) + +void YellowNote::resized(int width, int height) { - bool sv = false; - - if (_color_changed) { - _color_changed = true; - sv = true; - } - - bool hidden = !gtk_widget_is_visible(_note_widget); - if (hidden != _hidden) { - _hidden = hidden; - sv = true; - } - - int w, h; - gtk_window_get_size(_note_widget, &w, &h); - if (w < 50) { w = 50; } - if (_width != w) { - _width = w; - sv = true; - } - - if (h < 50) { h = 50; } - if (_height != h) { - _height = h; - sv = true; - } - - int x, y; - gtk_window_get_position(_note_widget, &x, &y); - if (x <= 0) { x = 1; } - if (y <= 0) { y = 1; } - if (_x != x) { - _x = x; - sv = true; - } - if (_y != y) { - _y = y; - sv = true; - } - - const char *c_t = gtk_label_get_text (_title_label); - if (c_t != nullptr) { - std::string t(c_t); - if (t != _title) { - _title = t; - sv = true; - } - } - - if (sv) { save(); } + _width = width; + _height = height; + save(); } -void YellowNote::size_allocated(GtkWidget *sender, GtkAllocation *a) +void YellowNote::size_allocated(GtkWidget *sender, GtkAllocation *alloc) { - changed(sender); + std::cout << "loaded: " << _size_loaded << ", " << _pos_loaded << std::endl; + int width = alloc->width; + int height = alloc->height; + //if (_size_loaded) { + std::cout << "width, height = " << width << ", " << height << std::endl; + // _width = width; + // _height = height; + // save(); + // } + if (!_moving) { + if (width != _width || height != _height) { + gtk_window_resize(_note_widget, _width, _height); + } + } +} + +void YellowNote::positioned(GtkWidget *sender, int x, int y) +{ + if (_pos_loaded) { + _x = x; + _y = y; + save(); + } } void YellowNote::toFront() @@ -941,11 +1171,31 @@ void YellowNote::toFront() gtk_window_move(_note_widget, _x, _y); gtk_widget_hide(_note_widget); } else { + std::cout << "to_front x = " << _x << std::endl; + int x = _x; + int y = _y; gtk_window_present(_note_widget); - gtk_window_move(_note_widget, _x, _y); + gtk_window_move(_note_widget, x, y); } } + +void YellowNote::toDesktop() +{ +#ifdef __linux + std::cout << "todesktop: width: " << _width << ", height: " << _height << std::endl; + gtk_window_set_type_hint(_note_widget, GdkWindowTypeHint::GDK_WINDOW_TYPE_HINT_DESKTOP); +#endif +} + +void YellowNote::fromDesktop() +{ +#ifdef __linux + gtk_window_set_type_hint(_note_widget, GdkWindowTypeHint::GDK_WINDOW_TYPE_HINT_UTILITY); +#endif + toFront(); +} + void YellowNote::get_header_screen_coords(int &header_top, int &header_bottom) { int left, top; @@ -1000,6 +1250,9 @@ void YellowNote::adjustTitle(bool mutate) gtk_container_add(_note_header, _delete_image); gtk_container_remove(_note_header, _hide_image); gtk_container_add(_note_header, _hide_image); + gtk_container_remove(_note_header, _to_desktop_image); + gtk_container_add(_note_header, _to_desktop_image); + } bool YellowNote::windowPresented(void *sender, GdkEventVisibility *evt) // TODO according to docs this must not be a pointer @@ -1021,10 +1274,8 @@ void YellowNote::textChanged(void *sender) { if (_in_transaction) return; - std::cout << "Changed " << _save_id << std::endl; _save_counter++; if (_save_id == -1) { - std::cout << "Starting save timer" << std::endl; _save_id = _save_counter; g_timeout_add(1000, on_text_save_timeout, this); } @@ -1033,13 +1284,11 @@ void YellowNote::textChanged(void *sender) bool YellowNote::textSaveTimeout() { if (_save_counter != _save_id) { - std::cout << "Something changed" << std::endl; _save_id = _save_counter; g_timeout_add(1000, on_text_save_timeout, this); return false; } else { _save_id = -1; - std::cout << "Saving" << std::endl; save(); return false; } @@ -1070,6 +1319,21 @@ bool YellowNote::titleFocusOut(GtkWidget *sender, GdkEventFocus *evt) #define AROUND(c, n) ((c >= (n - threshold)) && (c <= (n + threshold))) +gboolean is_dblclk(gpointer d) +{ + YellowNote *n = static_cast(d); + n->doubleClicked(); + return false; + +} + +void YellowNote::doubleClicked() +{ + if (!_double_clicked) { + _notes->notesFromDesktop(nullptr); + } +} + bool YellowNote::move_begin(GtkWidget *sender, GdkEventButton *evt) { int x = evt->x_root; @@ -1093,6 +1357,9 @@ bool YellowNote::move_begin(GtkWidget *sender, GdkEventButton *evt) int hide_left, hide_right; get_screen_left_right(_hide_image, hide_left, hide_right); + int to_desktop_left, to_desktop_right; + get_screen_left_right(_to_desktop_image, to_desktop_left, to_desktop_right); + if (y >= header_top && y <= header_bottom) { if (x >= color_left && x <= color_right) { nextColor(); @@ -1106,6 +1373,10 @@ bool YellowNote::move_begin(GtkWidget *sender, GdkEventButton *evt) hide(); return true; } + if (x >= to_desktop_left && x <= to_desktop_right) { + _notes->notesToDesktop(this); + return true; + } if (x >= delete_left && x <= delete_right) { deleteMe(); return true; @@ -1121,17 +1392,22 @@ bool YellowNote::move_begin(GtkWidget *sender, GdkEventButton *evt) gtk_container_add(_note_header, _delete_image); gtk_container_remove(_note_header, _hide_image); gtk_container_add(_note_header, _hide_image); + gtk_container_remove(_note_header, _to_desktop_image); + gtk_container_add(_note_header, _to_desktop_image); gtk_widget_show(_title_entry); gtk_entry_set_text(_title_entry, _title.c_str()); gtk_widget_grab_focus(_title_entry); _editing_title = true; + _double_clicked = true; return true; } + _double_clicked = false; if (y >= header_top && y <= header_bottom) { _moving = true; _x_orig = evt->x; _y_orig = evt->y; + g_timeout_add(250, is_dblclk, this); return true; } @@ -1172,11 +1448,13 @@ bool YellowNote::moving(GtkWidget *sender, GdkEventMotion *evt) if (_moving) { int the_x = x - _x_orig; int the_y = y - _y_orig; + std::cout << "moving" << std::endl; gtk_window_move(_note_widget, the_x, the_y); + positioned(_note_widget, the_x, the_y); return true; } - if (_resize_bottom || _resize_right || _resize_edge) { + if (_resize_bottom || _resize_right || _resize_edge) { if (_resize_edge) { int left, top; gtk_window_get_position(_note_widget, &left, &top); @@ -1185,6 +1463,9 @@ bool YellowNote::moving(GtkWidget *sender, GdkEventMotion *evt) if (width < 100) { width = 100; } if (height < 60) { height = 60; } gtk_window_resize(_note_widget, width, height); + resized(width, height); + + //size_allocated(_note_box, width, height); return true; } @@ -1196,6 +1477,8 @@ bool YellowNote::moving(GtkWidget *sender, GdkEventMotion *evt) int width = x - left; if (width < 100) { width = 100; } gtk_window_resize(_note_widget, width, h); + resized(width, h); + //size_allocated(_note_box, width, h); return true; } @@ -1207,12 +1490,14 @@ bool YellowNote::moving(GtkWidget *sender, GdkEventMotion *evt) int height = y - top; if (height < 60) { height = 60; } gtk_window_resize(_note_widget, w, height); + resized(w, height); + //size_allocated(_note_box, w, height); return true; } } - int frame_bottom, frame_right; - get_frame_screen_coords(frame_bottom, frame_right); + int frame_bottom, frame_right; + get_frame_screen_coords(frame_bottom, frame_right); int header_top, header_bottom; get_header_screen_coords(header_top, header_bottom); @@ -1258,47 +1543,64 @@ void YellowNote::load() std::filesystem::path p(_filename); + int hidden, x, y, width, height; + ColorType_t c; + std::string title; + size_t s = 0; if (std::filesystem::is_regular_file(p)) { s = std::filesystem::file_size(p); + + FILE *f = fopen(_filename.c_str(), "rt"); + + if (f) { + int version = readInt(f, -1); + + hidden = readInt(f, -1); + x = readInt(f, 200); + y = readInt(f, 200); + width = readInt(f, 300); + height = readInt(f, 200); + + int color; + color = readInt(f, ColorType_t::YELLOW); + c = static_cast(color); + + char *buf = static_cast(malloc(s)); + memset(buf, 0, s); + + fgets(buf, s, f); + title = buf; + trim(title); + + memset(buf, 0, s); + int pos = ftell(f); + int bytes = s - pos; + fread(buf, bytes, 1, f); + + fclose(f); + gtk_text_buffer_set_text(_buffer, buf, strlen(buf)); + free(buf); + + _title = title; + updateTitle(); + + _color = c; + updateColor(); + + _x = x; _y = y; + _pos_loaded = true; + updatePosition(); + + _width = width; _height = height; + _size_loaded = true; + updateSize(); + + _hidden = hidden; + _hidden_loaded = true; + updateHidden(); + } } - FILE *f = fopen(_filename.c_str(), "rt"); - - if (f) { - int version = readInt(f, -1); - - _hidden = readInt(f, -1); - _x = readInt(f, 200); - _y = readInt(f, 200); - _width = readInt(f, 300); - _height = readInt(f, 200); - - int color; - color = readInt(f, ColorType_t::YELLOW); - _color = static_cast(color); - - char *buf = static_cast(malloc(s)); - memset(buf, 0, s); - - fgets(buf, s, f); - _title = buf; - trim(_title); - - memset(buf, 0, s); - int pos = ftell(f); - int bytes = s - pos; - fread(buf, bytes, 1, f); - - fclose(f); - gtk_text_buffer_set_text(_buffer, buf, strlen(buf)); - free(buf); - } - - updateTitle(); - updateColor(); - updatePosition(); - updateSize(); - updateHidden(); _in_transaction = false; } @@ -1309,6 +1611,8 @@ void YellowNote::save() return; } + std::cout << "Saving " << _title << "..." << _size_loaded << ", " << _width << ", h = " << _height << std::endl; + std::filesystem::path p(_filename); FILE *f = fopen(_filename.c_str(), "wt"); if (f) { diff --git a/yellownotes.h b/yellownotes.h index 11d02d5..be20dce 100644 --- a/yellownotes.h +++ b/yellownotes.h @@ -10,6 +10,7 @@ extern "C" { } class YellowNote; +class ColorSet; typedef enum { DARK = 0, @@ -32,6 +33,8 @@ private: void *_dlg; void *_langs; + std::list _color_sets; + std::list _notes; int _font_size; GtkWindow *_toplevel; @@ -58,6 +61,8 @@ public: void popupTrayMenu(void *sender); void newNote(void *sender); void showNotes(void *sender); + void notesToDesktop(void *sender); + void notesFromDesktop(void *sender); void reloadNotes(void *sender); void quit(void *sender); void topLevelHidden(GtkWidget *sender); @@ -70,10 +75,19 @@ public: public: std::string currentLang(); void setCurrentLang(const std::string &l); + bool cfgOnDesktop(); + void setCfgOnDesktop(bool y); + std::string getFgColor(ColorType_t type); + std::string getBgColor(ColorType_t type); + void setFgColor(ColorType_t type, const std::string &col); + void setBgColor(ColorType_t type, const std::string &col); + std::string fromRGBA(const GdkRGBA &rgba); + void toRGBA(const std::string &col, GdkRGBA &rgba); public: YellowNotes(void *app); ~YellowNotes(); + void colorSet(void *sender); }; #define YELLOWNOTES(obj) reinterpret_cast(obj)