diff --git a/AUTHORS.txt b/AUTHORS.txt index 6cf6a632..92322a8b 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -21,8 +21,10 @@ THANKS TO Boost http://www.boost.org/ Doxygen http://www.doxygen.org/ GCC http://gcc.gnu.org/ + GTK+ http://www.gtk.org/ MinGW http://www.mingw.org/ Scintilla http://www.scintilla.org/ Wine http://www.winehq.com/ + wxWidgets http://www.wxwidgets.org/ ---------------------------------------------------------------------- diff --git a/LICENSE.txt b/LICENSE.txt index b6267152..a5243bd3 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ Vaca - Visual Application Components Abstraction -Copyright (c) 2005, 2006, David A. Capello +Copyright (c) 2005, 2006, 2007, 2008, David A. Capello All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Makefile.msc b/Makefile.msc index a5c886a2..03beabd0 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -49,19 +49,20 @@ OBJS = obj/Anchor.obj obj/AnchorLayout.obj obj/Application.obj \ obj/DockBar.obj obj/DockFrame.obj obj/DropFilesEvent.obj \ obj/Edit.obj obj/Event.obj obj/FileDialog.obj obj/FindTextDialog.obj \ obj/Font.obj obj/FontDialog.obj obj/Frame.obj obj/Graphics.obj \ - obj/GraphicsPath.obj obj/GroupBox.obj obj/Icon.obj obj/Image.obj \ - obj/ImageList.obj obj/KeyEvent.obj obj/Keys.obj obj/Label.obj \ - obj/Layout.obj obj/LinkLabel.obj obj/ListBox.obj obj/ListView.obj \ - obj/Mdi.obj obj/Menu.obj obj/MenuItemEvent.obj obj/MouseEvent.obj \ - obj/MsgBox.obj obj/Mutex.obj obj/Panel.obj obj/Pen.obj obj/Point.obj \ + obj/GraphicsPath.obj obj/GroupBox.obj obj/HttpRequest.obj \ + obj/Icon.obj obj/Image.obj obj/ImageList.obj obj/KeyEvent.obj \ + obj/Keys.obj obj/Label.obj obj/Layout.obj obj/LinkLabel.obj \ + obj/ListBox.obj obj/ListView.obj obj/Mdi.obj obj/Menu.obj \ + obj/MenuItemEvent.obj obj/MouseEvent.obj obj/MsgBox.obj \ + obj/Mutex.obj obj/Panel.obj obj/Pen.obj obj/Point.obj \ obj/ProgressBar.obj obj/RadioButton.obj obj/ReBar.obj obj/Rect.obj \ - obj/Region.obj obj/ResourceId.obj obj/Scintilla.obj \ - obj/Separator.obj obj/Size.obj obj/Slider.obj obj/SpinButton.obj \ - obj/Spinner.obj obj/String.obj obj/Style.obj obj/System.obj \ - obj/Tab.obj obj/Thread.obj obj/TimePoint.obj obj/Timer.obj \ - obj/ToggleButton.obj obj/ToolBar.obj obj/TreeNode.obj \ - obj/TreeView.obj obj/TreeViewEvent.obj obj/Vaca.obj obj/Widget.obj \ - obj/WidgetClass.obj + obj/Referenceable.obj obj/Region.obj obj/ResourceId.obj \ + obj/Scintilla.obj obj/Separator.obj obj/Size.obj obj/Slider.obj \ + obj/SpinButton.obj obj/Spinner.obj obj/StatusBar.obj obj/String.obj \ + obj/Style.obj obj/System.obj obj/Tab.obj obj/Thread.obj \ + obj/TimePoint.obj obj/Timer.obj obj/ToggleButton.obj obj/ToolBar.obj \ + obj/TreeNode.obj obj/TreeView.obj obj/TreeViewEvent.obj obj/Vaca.obj \ + obj/Widget.obj obj/WidgetClass.obj EXAMPLES_EXE = bin/AnchorLayouts.exe bin/AutoCompletion.exe \ bin/Bixes.exe bin/BouncingBalls.exe bin/BoxLayouts.exe \ @@ -70,16 +71,25 @@ EXAMPLES_EXE = bin/AnchorLayouts.exe bin/AutoCompletion.exe \ bin/Edits.exe bin/EyeDropper.exe bin/FontMetrics.exe \ bin/FreeOfLayout.exe bin/Hashing.exe bin/HelloWorld.exe \ bin/Images.exe bin/Labels.exe bin/LikeScript.exe bin/Maths.exe \ - bin/MenuResource.exe bin/MiniExplorer.exe bin/PensBrushes.exe \ - bin/Primitives.exe bin/ProgressBars.exe bin/Regions.exe \ - bin/Scribble.exe bin/Sliders.exe bin/Spinners.exe \ + bin/MenuResource.exe bin/MiniExplorer.exe bin/Minimal.exe \ + bin/Paths.exe bin/Primitives.exe bin/ProgressBars.exe \ + bin/Regions.exe bin/Scribble.exe bin/Sliders.exe bin/Spinners.exe \ bin/StdCommands.exe bin/Sudoku.exe bin/SystemImageList.exe \ bin/Tabs.exe bin/TextEditor.exe bin/Threads.exe bin/Timers.exe \ bin/ToolBars.exe bin/Trees.exe bin/Undo.exe bin/WebCam.exe -TESTS_EXE = bin/test_bind.exe bin/test_menu.exe bin/test_point.exe \ - bin/test_rect.exe bin/test_signal.exe bin/test_size.exe \ - bin/test_string.exe bin/test_thread.exe +TESTS_EXE = \ + bin/test_bind.exe \ + bin/test_menu.exe \ + bin/test_point.exe \ + bin/test_rect.exe \ + bin/test_region.exe \ + bin/test_signal.exe \ + bin/test_size.exe \ + bin/test_smartptr.exe \ + bin/test_string.exe \ + bin/test_tab.exe \ + bin/test_thread.exe # ---------------------------------------------------------------------- # Rules @@ -167,7 +177,8 @@ bin/LikeScript.exe: obj/LikeScript.obj obj/Example.res bin/Maths.exe: obj/Maths.obj obj/Example.res bin/MenuResource.exe: obj/MenuResource.obj obj/MenuResource.res bin/MiniExplorer.exe: obj/MiniExplorer.obj obj/Example.res -bin/PensBrushes.exe: obj/PensBrushes.obj obj/Example.res +bin/Minimal.exe: obj/Minimal.obj obj/Example.res +bin/Paths.exe: obj/Paths.obj obj/Example.res bin/Primitives.exe: obj/Primitives.obj obj/Example.res bin/ProgressBars.exe: obj/ProgressBars.obj obj/Example.res bin/Regions.exe: obj/Regions.obj obj/Example.res @@ -262,8 +273,10 @@ obj/MenuResource.obj: examples/MenuResource/MenuResource.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c examples/MenuResource/MenuResource.cpp obj/MiniExplorer.obj: examples/MiniExplorer/MiniExplorer.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c examples/MiniExplorer/MiniExplorer.cpp -obj/PensBrushes.obj: examples/PensBrushes/PensBrushes.cpp - $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c examples/PensBrushes/PensBrushes.cpp +obj/Minimal.obj: examples/Minimal/Minimal.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c examples/Minimal/Minimal.cpp +obj/Paths.obj: examples/Paths/Paths.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c examples/Paths/Paths.cpp obj/Primitives.obj: examples/Primitives/Primitives.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c examples/Primitives/Primitives.cpp obj/ProgressBars.obj: examples/ProgressBars/ProgressBars.cpp @@ -305,13 +318,33 @@ obj/WebCam.obj: examples/WebCam/WebCam.cpp obj/test_bind.obj: tests/test_bind.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_bind.cpp + +obj/test_menu.obj: tests/test_menu.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_menu.cpp + obj/test_point.obj: tests/test_point.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_point.cpp + obj/test_rect.obj: tests/test_rect.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_rect.cpp + +obj/test_region.obj: tests/test_region.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_region.cpp + obj/test_signal.obj: tests/test_signal.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_signal.cpp + obj/test_size.obj: tests/test_size.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_size.cpp + +obj/test_smartptr.obj: tests/test_smartptr.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_smartptr.cpp + obj/test_string.obj: tests/test_string.cpp $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_string.cpp + +obj/test_tab.obj: tests/test_tab.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_tab.cpp + +obj/test_thread.obj: tests/test_thread.cpp + $(CPP) -nologo $(CPPFLAGS) -Foobj/ -c tests/test_thread.cpp diff --git a/NEWS.txt b/NEWS.txt index 94cc1f2e..c99deeae 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,26 +1,25 @@ Vaca 0.0.7 -- ~Widget now destroys automatically the widget's children. - Added MenuPopup. -- Renamed MouseButtons to MouseButton. - Added RefWrapper class and Ref() method to support references in Bind(). - Added GraphicsPath. +- Added HttpRequest class. +- Added FontMetrics class. +- Added StatusBar widget. Now Frame has an associated StatusBar. +- Added Separator widget. +- Added RadioGroup::onChange event/signal. - All methods that return Win32 handles (HWND, HDC, HBRUSH, HRGN, etc.) now are called getHandle(). +- Added GdiObject and SmartPtr. - Brush, Cursor, Font, Icon, Image, ImageList, Pen, and Region are SmartPtrs. -- Added GdiObject and SmartPtr. - Widget destructor deletes children. -- Added HttpRequest class. -- Added FontMetrics class. +- Renamed MouseButtons to MouseButton. - Renamed Borders to Sides. -- Added StatusBar widget. Now Frame has an associated StatusBar. -- Added Separator widget. -- Added RadioGroup::onChange event/signal. - Fixed Bix::getPreferredSize when EvenX or EvenY flags are activated. - Now MenuItem::setEnabled/Checked can be used although the item isn't in a parent Menu. -- Removed SelfDestruction class. +- Removed SelfDestruction class (with SmartPtrs isn't needed anymore). Vaca 0.0.6 diff --git a/README.txt b/README.txt index 737b0d6f..1358062e 100644 --- a/README.txt +++ b/README.txt @@ -1,10 +1,17 @@ Vaca - Visual Application Components Abstraction - Copyright (c) 2005, 2006, David A. Capello + Copyright (c) 2005, 2006, 2007, 2008, David A. Capello All rights reserved. -- - Vaca is a library to wrap the Win32 API with C++ classes. Also, it's - has some extra functionalities like dockable tool bars and layout - managers. This library uses templates (but not generic programming), - and Boost (the Boost.Signals library is just perfect). + Vaca is a library to develop GUI applications with C++. + It uses templates and STL, and has some special features like + dockable tool bars and layout managers. + + Vaca is a wrapper for the Win32 API. What is the Win32 API? You don't + need to know about it, but it is the set of routines that Microsoft + gives you to program applications on Windows. + + -- + + http://vaca.sourceforge.net/ diff --git a/TODO.txt b/TODO.txt index a4bcdad2..7b7da9aa 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,7 +2,7 @@ General ---------------------------------------------------------------------- -- Look at 'TODO' in source code +- Look at 'TODO' or '@todo' in source code ---------------------------------------------------------------------- @@ -31,12 +31,9 @@ Widgets Examples ---------------------------------------------------------------------- -- FontMetrics (finish it) -- PensBrushes (finish Brushes stuff) - DataGrids (complete) - Sudoku (double-buffered, with better hot-tracking, better cell handle, and fix the "infinite-loop" bug in the level generator) -- Remove CommandsAlt, LikeDOS, ThreadKiller - Finish Xuls or GridLayout @@ -65,8 +62,6 @@ API - Add support for FlashWindowEx. -- See what to do with the Command class. - - Remember the WM_MENUSELECT message for status-bars. - add support for DrawFrameControl, DrawState, DrawEdge @@ -78,7 +73,3 @@ API - mouseHover should be? (there is already some code) - a "MVC: Model View Controller" pattern (also known as Observer pattern). - -- Graphics::widenPath() - -- finish GraphicsPath class diff --git a/doc/pages/classes.h b/doc/pages/classes.h index 6297e8fb..70702b42 100644 --- a/doc/pages/classes.h +++ b/doc/pages/classes.h @@ -7,8 +7,8 @@ namespace Vaca { @li @ref page_classes_base @li @ref page_classes_app @li @ref page_classes_graphics -@li @ref page_classes_mess @li @ref page_classes_widgets +@li @ref page_classes_mess @li @ref page_classes_cmds @li @ref page_classes_menus @li @ref page_classes_layout @@ -68,35 +68,6 @@ namespace Vaca { @endTable -@section page_classes_mess MESS - -@beginOverviewTable -@titleRow{Messages} - @itemRow{Message} -@titleRow{Events} - @itemRow{CancelableEvent} - @itemRow{CloseEvent} - @itemRow{DropFilesEvent} - @itemRow{Event} - @itemRow{KeyEvent} - @itemRow{ListViewEvent} - @itemRow{MenuItemEvent} - @itemRow{MouseEvent} - @itemRow{SpinButtonEvent} - @itemRow{TreeViewEvent} -@titleRow{Signals} - @itemRow{Signal0} - @itemRow{Signal1} - @itemRow{Signal2} -@titleRow{Slots} - @itemRow{Slot0} - @itemRow{Slot1} - @itemRow{Slot2} -@titleRow{Other} - @itemRow{RefWrapper} -@endTable - - @section page_classes_widgets Widgets @beginOverviewTable @@ -178,6 +149,35 @@ namespace Vaca { @endTable +@section page_classes_mess MESS + +@beginOverviewTable +@titleRow{Messages} + @itemRow{Message} +@titleRow{Events} + @itemRow{CancelableEvent} + @itemRow{CloseEvent} + @itemRow{DropFilesEvent} + @itemRow{Event} + @itemRow{KeyEvent} + @itemRow{ListViewEvent} + @itemRow{MenuItemEvent} + @itemRow{MouseEvent} + @itemRow{SpinButtonEvent} + @itemRow{TreeViewEvent} +@titleRow{Signals} + @itemRow{Signal0} + @itemRow{Signal1} + @itemRow{Signal2} +@titleRow{Slots} + @itemRow{Slot0} + @itemRow{Slot1} + @itemRow{Slot2} +@titleRow{Other} + @itemRow{RefWrapper} +@endTable + + @section page_classes_cmds Commands @beginOverviewTable diff --git a/doc/pages/debug.h b/doc/pages/debug.h index 43d63db5..c9b2bed6 100644 --- a/doc/pages/debug.h +++ b/doc/pages/debug.h @@ -6,8 +6,13 @@ namespace Vaca { @li @ref page_debug_log + @section page_debug_log Log file +A log file called "vaca.log" is created when you use the debug version +of Vaca library. It contains all the output create with +the @ref VACA_TRACE macro. + */ } diff --git a/doc/pages/examples.h b/doc/pages/examples.h index df6e1e0a..45777984 100644 --- a/doc/pages/examples.h +++ b/doc/pages/examples.h @@ -205,10 +205,12 @@ memory leaks (Image is a SmartPtr). @section page_examples_webcam WebCam Example +@win32 This example shows how to override the Widget#createHandle method to create your own HWND. It uses the Video for Windows (VfW) API. +@endwin32 */ diff --git a/doc/pages/functions.h b/doc/pages/functions.h index 8f98c485..4c06a177 100644 --- a/doc/pages/functions.h +++ b/doc/pages/functions.h @@ -16,6 +16,8 @@ namespace Vaca { @titleRow{Bindings} @itemRow{page_bind, Adapts functions or methods to be connected to signals.} @itemRow{Ref} +@titleRow{Debug} + @itemRow{VACA_TRACE} @endTable */ diff --git a/examples/FontMetrics/FontMetrics.cpp b/examples/FontMetrics/FontMetrics.cpp index 320261fb..8aa6b74e 100644 --- a/examples/FontMetrics/FontMetrics.cpp +++ b/examples/FontMetrics/FontMetrics.cpp @@ -44,7 +44,6 @@ class MainFrame : public Frame MainFrame() : Frame("FontMetrics") - // , m_sampleText("abgijqM\r\nAbc") , m_sampleText("abgijqM") , m_font("Times New Roman", 128) { @@ -54,30 +53,6 @@ class MainFrame : public Frame setDoubleBuffered(true); } -// virtual void onGotFocus(Event &ev) -// { -// Frame::onGotFocus(ev); - -// // caret position -// Rect rc = getClientBounds(); -// ScreenGraphics g; -// g.setFont(&m_font); -// Size textSize = g.measureString(m_sampleText); -// Point origin = rc.getCenter()-Point(textSize/2); - -// CreateCaret(getHandle(), NULL, 1, g.measureString("tmp").h); -// ShowCaret(getHandle()); -// SetCaretPos(origin.x, origin.y); -// } - -// virtual void onLostFocus(Event &ev) -// { -// Frame::onLostFocus(ev); - -// HideCaret(getHandle()); -// DestroyCaret(); -// } - // after the size is changed virtual void onResize(const Size &sz) { @@ -224,10 +199,6 @@ class MainFrame : public Frame output.setSize(g.measureString(chrText)); -// ABC abc; -// GetCharABCWidths(g.getHDC(), *it, *it, &abc); -// output.w = (abc.abcA+abc.abcB+abc.abcC) * 72 / GetDeviceCaps(g.getHDC(), LOGPIXELSX); - if (*it == '\r') { output.x = origin.x; } @@ -236,23 +207,11 @@ class MainFrame : public Frame } else { functor(g, chrText, color, output); - - // int interChr = GetTextCharacterExtra(g.getHDC()); - // output.x += output.w + interChr; output.x += output.w; } } } -// void onChangeFont(Font &font) -// { -// FontDialog dialog(&font, this); -// if (dialog.doModal()) { -// layout(); -// invalidate(false); -// } -// } - }; ////////////////////////////////////////////////////////////////////// diff --git a/examples/Paths/Paths.cpp b/examples/Paths/Paths.cpp index a58f9a6a..f48a20b6 100644 --- a/examples/Paths/Paths.cpp +++ b/examples/Paths/Paths.cpp @@ -65,6 +65,205 @@ class Figure const Pen& pen, const Brush& brush) : path(path), pen(pen), brush(brush) { } + + bool isClosed() const + { + // the last node in the path indicates if the path is closed or not + return (path.end()-1)->isCloseFigure(); + } + + void setClosed(bool state) + { + // the last node in the path indicates if the path is closed or not + (path.end()-1)->setCloseFigure(state); + } + +}; + +////////////////////////////////////////////////////////////////////// +// Dialog to edit figure properties + +class FigureProperties : public Dialog +{ + Figure& m_fig; + Figure m_figBackup; + // for Pen + Separator m_penInfo; + Label m_penLabel; + Label m_penWidthLabel; + Slider m_penWidthSlider; + Edit m_penWidthEdit; + Button m_penColor; + GroupBox m_endCapInfo; + RadioGroup m_endCapGroup; + RadioButton m_roundEndCap; + RadioButton m_squareEndCap; + RadioButton m_flatEndCap; + GroupBox m_joinInfo; + RadioGroup m_joinGroup; + RadioButton m_roundJoin; + RadioButton m_bevelJoin; + RadioButton m_miterJoin; + // for Brush + Separator m_brushInfo; + Label m_brushLabel; + Button m_brushColor; + // bottom + Separator m_separator; + CheckBox m_closeFigure; + Button m_ok; + Button m_cancel; + +public: + + // signal fired when the figure's properties are modified + // in the dialog + Signal0 Change; + + FigureProperties(Figure& fig, Widget* parent) + : Dialog("Figure Properties", parent) + , m_fig(fig) + , m_figBackup(fig) + , m_penInfo(this) + , m_penLabel("Pen configuration:", this) + , m_penWidthLabel("Width:", this) + , m_penWidthSlider(1, 64, 32, this) + , m_penWidthEdit("", this, EditStyle + ReadOnlyEditStyle) + , m_penColor("Color", this) + , m_endCapInfo("End Cap", this) + , m_roundEndCap("Round", m_endCapGroup, &m_endCapInfo) + , m_squareEndCap("Square", m_endCapGroup, &m_endCapInfo) + , m_flatEndCap("Flat", m_endCapGroup, &m_endCapInfo) + , m_joinInfo("Join", this) + , m_roundJoin("Round", m_joinGroup, &m_joinInfo) + , m_bevelJoin("Bevel", m_joinGroup, &m_joinInfo) + , m_miterJoin("Miter", m_joinGroup, &m_joinInfo) + , m_brushInfo(this) + , m_brushLabel("Brush configuration:", this) + , m_brushColor("Color", this) + , m_separator(this) + , m_closeFigure("Close Figure", this) + , m_ok("&OK", this) + , m_cancel("Cancel", this) + { + // preferred size for the Edit control of the pen-width + m_penWidthEdit.setPreferredSize(Size(32, m_penWidthEdit.getPreferredSize().h)); + + // this two labels will have boldface + m_penLabel.setFont(Font(getFont(), FontStyle::Italic)); + m_brushLabel.setFont(Font(getFont(), FontStyle::Italic)); + + // layout managers + setLayout(Bix::parse("Y[%,%,Y[X[%,f%,%],X[f%,f%,Y[%]]],%,%,X[%],%,X[f%,eX[%,%]]]", + &m_penInfo, + &m_penLabel, + &m_penWidthLabel, &m_penWidthSlider, &m_penWidthEdit, + &m_endCapInfo, &m_joinInfo, &m_penColor, + &m_brushInfo, + &m_brushLabel, + &m_brushColor, + &m_separator, + &m_closeFigure, &m_ok, &m_cancel)); + m_endCapInfo.setLayout(new BoxLayout(Orientation::Vertical, false)); + m_joinInfo.setLayout(new BoxLayout(Orientation::Vertical, false)); + + initValues(); + + // signals/slots + m_ok.Action.connect(Bind(&FigureProperties::defaultOkAction, this)); + m_cancel.Action.connect(Bind(&FigureProperties::onCancel, this)); + + m_penWidthSlider.Change.connect(Bind(&FigureProperties::onPenChange, this)); + m_endCapGroup.Change.connect(Bind(&FigureProperties::onPenChange, this)); + m_joinGroup.Change.connect(Bind(&FigureProperties::onPenChange, this)); + + m_penColor.Action.connect(Bind(&FigureProperties::onSelectPenColor, this)); + m_brushColor.Action.connect(Bind(&FigureProperties::onSelectBrushColor, this)); + m_closeFigure.Action.connect(Bind(&FigureProperties::onCloseFigure, this)); + + // center the dialog + setSize(getPreferredSize()); + center(); + } + +private: + + // fill the widgets through the current figure values + void initValues() + { + m_penWidthSlider.setValue(m_fig.pen.getWidth()); + m_penWidthEdit.setText(String::fromInt(m_fig.pen.getWidth())); + + m_endCapGroup.setSelectedIndex(m_fig.pen.getEndCap()); + m_joinGroup.setSelectedIndex(m_fig.pen.getJoin()); + + m_closeFigure.setSelected(m_fig.isClosed()); + } + + // If the user presses the Cancel button, then we have to restore to + // the old figure properties + void onCancel() + { + // restore the figure configuration + m_fig = m_figBackup; + + // fire the Change signal to indicate that the figure has changed + Change(); + + // close the dialog + defaultCancelAction(); + } + + void onPenChange() + { + m_fig.pen = createPen(m_fig.pen.getColor()); + Change(); + } + + void onSelectPenColor() + { + ColorDialog dlg(m_fig.pen.getColor(), this); + if (dlg.doModal()) { + m_fig.pen = createPen(dlg.getColor()); + Change(); + } + } + + void onSelectBrushColor() + { + ColorDialog dlg(m_fig.brush.getColor(), this); + if (dlg.doModal()) { + m_fig.brush = Brush(dlg.getColor()); + Change(); + } + } + + void onCloseFigure() + { + m_fig.setClosed(m_closeFigure.isSelected()); + Change(); + } + + Pen createPen(const Color& color) + { + PenEndCap endCap; + PenJoin join; + switch (m_endCapGroup.getSelectedIndex()) { + case 0: endCap = PenEndCap::Round; break; + case 1: endCap = PenEndCap::Square; break; + case 2: endCap = PenEndCap::Flat; break; + } + switch (m_joinGroup.getSelectedIndex()) { + case 0: join = PenJoin::Round; break; + case 1: join = PenJoin::Bevel; break; + case 2: join = PenJoin::Miter; break; + } + return Pen(color, + m_penWidthSlider.getValue(), + PenStyle::Solid, + endCap, join); + } + }; ////////////////////////////////////////////////////////////////////// @@ -78,7 +277,7 @@ class FigsEditor : public Panel typedef std::list
Figs; Figs m_figs; // list of figures - Figs::iterator m_hotFigure; // the figure that has the mouse above + Figs::iterator m_selFigure; // selected figure GraphicsPath::iterator m_hotNode; // the path's node that has the mouse above GraphicsPath::iterator m_relNode; // related bezier control node to 'm_hotNode' node GraphicsPath m_newPath; // the temporary path that is being modified @@ -97,7 +296,7 @@ class FigsEditor : public Panel // create a figure by default createNewFigure(Point(80, 80)); - m_hotFigure = NULLFIGURE; + m_selFigure = NULLFIGURE; m_hotNode = NULLNODE; } @@ -108,10 +307,15 @@ class FigsEditor : public Panel { Panel::onMouseDown(ev); - // update which object (node/figure) is hot - updateHot(ev.getPoint()); + // if we have the capture here is because the user pressed another + // button but without releasing the first one + if (hasCapture()) + return; + m_moved = false; + // first check if we are above a node of the current selected figure + updateHotNode(ev.getPoint()); if (m_hotNode != NULLNODE) { m_oldPoint = ev.getPoint(); @@ -125,14 +329,18 @@ class FigsEditor : public Panel captureMouse(); } - else if (m_hotFigure != NULLFIGURE) { - m_newPath = m_hotFigure->path; - m_hotNode = NULLNODE; - m_oldPoint = ev.getPoint(); - captureMouse(); - } - else if (ev.getButton() == MouseButton::Right) { - showPopupMenuForBackground(ev.getPoint()); + else { + // check if with this click we change the current selected figure + updateSelectedFigure(ev.getPoint()); + if (m_selFigure != NULLFIGURE) { + m_oldPoint = ev.getPoint(); + captureMouse(); + } + // if the user select in the background we can show the menu to + // create new figures + else if (ev.getButton() == MouseButton::Right) { + showPopupMenuForBackground(ev.getPoint()); + } } } @@ -161,7 +369,7 @@ class FigsEditor : public Panel m_oldPoint = ev.getPoint(); } else { - updateHot(ev.getPoint()); + updateHotNode(ev.getPoint()); } } @@ -173,14 +381,14 @@ class FigsEditor : public Panel // when finish the node movement if (m_hotNode != NULLNODE) { - m_hotFigure->path = m_newPath; + m_selFigure->path = m_newPath; } // when finish the path movement else { switch (ev.getButton()) { case MouseButton::Left: case MouseButton::Middle: - m_hotFigure->path = m_newPath; + m_selFigure->path = m_newPath; break; case MouseButton::Right: { if (m_moved) @@ -195,7 +403,6 @@ class FigsEditor : public Panel } } - m_hotFigure = NULLFIGURE; m_hotNode = NULLNODE; m_relNode = NULLNODE; invalidate(true); @@ -208,14 +415,18 @@ class FigsEditor : public Panel // stroke and fill all figures for (Figs::reverse_iterator it=m_figs.rbegin(); it!=m_figs.rend(); ++it) { - // stroke & fill the path of this figure - g.strokeAndFillPath(it->path, it->pen, it->brush, Point(0, 0)); + // stroke & fill the closed paths + if (it->isClosed()) + g.strokeAndFillPath(it->path, it->pen, it->brush, Point(0, 0)); + // only stroke opened paths + else + g.strokePath(it->path, it->pen, Point(0, 0)); } - // there are a hot figure? - if (m_hotFigure != NULLFIGURE) - drawHotPath(g, hasCapture() ? m_newPath: - m_hotFigure->path); + // there are a selected figure? + if (m_selFigure != NULLFIGURE) + drawSelectedPath(g, hasCapture() ? m_newPath: + m_selFigure->path); // there are a hot node? if (m_hotNode != NULLNODE) { @@ -234,10 +445,12 @@ class FigsEditor : public Panel void createNewFigure(const Point& putHere) { - Color color(rand()%200, rand()%200, rand()%200); + Color color(120+(rand()%80), + 120+(rand()%80), + 120+(rand()%80)); Figure fig; fig.pen = Pen(color, 3); - fig.brush = Brush(color*1.5); + fig.brush = Brush(color*1.3); // fig.path is a GraphicsPath fig.path @@ -251,40 +464,48 @@ class FigsEditor : public Panel m_figs.push_front(fig); } - void updateHot(const Point& hotSpot) + void updateSelectedFigure(const Point& hotSpot) { - // calculate the hot figure - Figs::iterator hotFig = NULLFIGURE; + Figs::iterator selFig = NULLFIGURE; + for (Figs::iterator it=m_figs.begin(); it!=m_figs.end(); ++it) { if (it->path.toRegion().contains(hotSpot)) { - hotFig = it; + selFig = it; break; } } - // calculate the hot node - GraphicsPath::iterator hotNode = NULLNODE; - for (Figs::iterator it=m_figs.begin(); it!=m_figs.end(); ++it) { - for (GraphicsPath::iterator it2=it->path.begin(); it2!=it->path.end(); ++it2) { - Point& pt = it2->getPoint(); - if (Rect(pt-Point(4,4), pt+Point(4,4)).contains(hotSpot)) { - m_newPath = it->path; - hotNode = m_newPath.begin() + (it2 - it->path.begin()); - hotFig = it; - break; - } + if (m_selFigure != selFig) { + m_selFigure = selFig; + invalidate(true); + + if (m_selFigure != NULLFIGURE) { + m_newPath = m_selFigure->path; } + else { + m_newPath = GraphicsPath(); + } + m_hotNode = NULLNODE; + } + } + + void updateHotNode(const Point& hotSpot) + { + GraphicsPath::iterator it; + + for (it=m_newPath.begin(); it!=m_newPath.end(); ++it) { + Point& pt = it->getPoint(); + if (Rect(pt-Point(4,4), pt+Point(4,4)).contains(hotSpot)) + break; } - if ((m_hotFigure != hotFig) || - (m_hotNode != hotNode)) { - m_hotFigure = hotFig; - m_hotNode = hotNode; + if (m_hotNode != it) { + m_hotNode = it; invalidate(true); } } - - void drawHotPath(Graphics& g, const GraphicsPath& path) + + void drawSelectedPath(Graphics& g, const GraphicsPath& path) { GraphicsPath::const_iterator it, end = path.end(); Pen pen(Color::Blue); @@ -342,12 +563,13 @@ class FigsEditor : public Panel if (CommandId id = menu.doModal(this, pt)) { switch (id) { case ID_MOVE_HERE: - m_hotFigure->path = m_newPath; + m_selFigure->path = m_newPath; break; case ID_COPY_HERE: m_figs.push_front(Figure(m_newPath, - m_hotFigure->pen, - m_hotFigure->brush)); + m_selFigure->pen, + m_selFigure->brush)); + m_selFigure = m_figs.begin(); break; } } @@ -369,33 +591,48 @@ class FigsEditor : public Panel switch (id) { case ID_CUT: case ID_COPY: { - m_clipboard = *m_hotFigure; + m_clipboard = *m_selFigure; Rect bounds = m_clipboard.path.toRegion().getBounds(); m_clipboard.path.offset(-bounds.getOrigin() - Point(bounds.getSize()/2)); - if (id == ID_CUT) - m_figs.erase(m_hotFigure); + if (id == ID_CUT) { + m_figs.erase(m_selFigure); + m_selFigure = NULLFIGURE; + } break; } case ID_REMOVE: - m_figs.erase(m_hotFigure); + m_figs.erase(m_selFigure); + m_selFigure = NULLFIGURE; break; case ID_FRONT: { - Figure copy = *m_hotFigure; - m_figs.erase(m_hotFigure); + Figure copy = *m_selFigure; + m_figs.erase(m_selFigure); m_figs.push_front(copy); + m_selFigure = m_figs.begin(); break; } case ID_BACK: { - Figure copy = *m_hotFigure; - m_figs.erase(m_hotFigure); + Figure copy = *m_selFigure; + m_figs.erase(m_selFigure); m_figs.push_back(copy); + m_selFigure = m_figs.end(); break; } - case ID_PROPERTIES: - // TODO + case ID_PROPERTIES: { + FigureProperties dlg(*m_selFigure, getParent()); + + // if the properties in dialog are changed, then we have to + // invalidate the editor so we can see the changes immediately + dlg.Change.connect(Bind(&FigsEditor::invalidate, this, true)); + + // show the dialog + dlg.doModal(); + + m_newPath = m_selFigure->path; break; + } } } } @@ -408,116 +645,16 @@ class FigsEditor : public Panel class MainFrame : public Frame { FigsEditor m_editor; - // CheckBox m_closeFigure; - // GroupBox m_penPanel; - // GroupBox m_brushPanel; - // for Pen - // Panel m_penLeftPanel; - // Label m_penWidthLabel; - // Slider m_penWidth; - // Button m_penColor; - // GroupBox m_endCapPanel; - // RadioGroup m_endCapGroup; - // RadioButton m_roundEndCap; - // RadioButton m_squareEndCap; - // RadioButton m_flatEndCap; - // GroupBox m_joinPanel; - // RadioGroup m_joinGroup; - // RadioButton m_roundJoin; - // RadioButton m_bevelJoin; - // RadioButton m_miterJoin; - // // for Brush - // Button m_brushColor; public: MainFrame() : Frame("Paths") , m_editor(this) - // , m_closeFigure("Close Figure", this) - // , m_penPanel("Pen", this) - // , m_brushPanel("Brush", this) - // , m_penLeftPanel(&m_penPanel) - // , m_penWidthLabel("Width:", &m_penLeftPanel) - // , m_penWidth(1, 64, 32, &m_penLeftPanel) - // , m_penColor("Color", &m_penLeftPanel) - // , m_endCapPanel("End Cap", &m_penPanel) - // , m_roundEndCap("Round", m_endCapGroup, &m_endCapPanel) - // , m_squareEndCap("Square", m_endCapGroup, &m_endCapPanel) - // , m_flatEndCap("Flat", m_endCapGroup, &m_endCapPanel) - // , m_joinPanel("Join", &m_penPanel) - // , m_roundJoin("Round", m_joinGroup, &m_joinPanel) - // , m_bevelJoin("Bevel", m_joinGroup, &m_joinPanel) - // , m_miterJoin("Miter", m_joinGroup, &m_joinPanel) - // , m_brushColor("Color", &m_brushPanel) { setLayout(new ClientLayout); - // setLayout(new BoxLayout(Orientation::Vertical, false)); - // m_editor.setConstraint(new BoxConstraint(true)); - // m_penPanel.setLayout(new BoxLayout(Orientation::Horizontal, true, 0)); - // m_penLeftPanel.setLayout(new BoxLayout(Orientation::Vertical, false, 0)); - // m_endCapPanel.setLayout(new BoxLayout(Orientation::Vertical, true, 0)); - // m_joinPanel.setLayout(new BoxLayout(Orientation::Vertical, true, 0)); - // m_brushPanel.setLayout(new BoxLayout(Orientation::Horizontal, false, 0)); - - // m_roundEndCap.setSelected(true); - // m_roundJoin.setSelected(true); - - // m_penWidth.Change.connect(Bind(&MainFrame::regenerate, this)); - // m_endCapGroup.Change.connect(Bind(&MainFrame::regenerate, this)); - // m_joinGroup.Change.connect(Bind(&MainFrame::regenerate, this)); - - // m_penColor.Action.connect(Bind(&MainFrame::onSelectPenColor, this)); - // m_brushColor.Action.connect(Bind(&MainFrame::onSelectBrushColor, this)); - // m_closeFigure.Action.connect(Bind(&MainFrame::onCloseFigure, this)); } -private: - - // void onSelectPenColor() - // { - // ColorDialog dlg(m_preview.getPen().getColor(), this); - // if (dlg.doModal()) - // m_preview.setPen(createPen(dlg.getColor())); - // } - - // void onSelectBrushColor() - // { - // ColorDialog dlg(m_preview.getBrush().getColor(), this); - // if (dlg.doModal()) - // m_preview.setBrush(Brush(dlg.getColor())); - // } - - // void onCloseFigure() - // { - // m_preview.setCloseFigure(m_closeFigure.isSelected()); - // } - - // void regenerate() - // { - // m_preview.setPen(createPen(m_preview.getPen().getColor())); - // } - - // Pen createPen(const Color& color) - // { - // PenEndCap endCap; - // PenJoin join; - // switch (m_endCapGroup.getSelectedIndex()) { - // case 0: endCap = PenEndCap::Round; break; - // case 1: endCap = PenEndCap::Square; break; - // case 2: endCap = PenEndCap::Flat; break; - // } - // switch (m_joinGroup.getSelectedIndex()) { - // case 0: join = PenJoin::Round; break; - // case 1: join = PenJoin::Bevel; break; - // case 2: join = PenJoin::Miter; break; - // } - // return Pen(color, - // m_penWidth.getValue(), - // PenStyle::Solid, - // endCap, join); - // } - }; ////////////////////////////////////////////////////////////////////// diff --git a/examples/Trees/Trees.cpp b/examples/Trees/Trees.cpp index eff20d6f..7ae7e6a7 100644 --- a/examples/Trees/Trees.cpp +++ b/examples/Trees/Trees.cpp @@ -93,7 +93,7 @@ class MainFrame : public Frame public: MainFrame() - : Frame("Trees") + : Frame("Trees (WIP)") , m_dragAndDrop1("Drag && Drop", this) , m_dragAndDrop2("Drag && Drop", this) , m_treeView1(this) diff --git a/include/Vaca/GraphicsPath.h b/include/Vaca/GraphicsPath.h index 1907ae5b..ddbe7861 100644 --- a/include/Vaca/GraphicsPath.h +++ b/include/Vaca/GraphicsPath.h @@ -73,19 +73,19 @@ class VACA_DLL GraphicsPath * @li a node of movement (MoveTo) to go to the line's start position, and * @li a node to draw a line (LineTo) that represent the end position of the line. */ - class Node + class VACA_DLL Node { friend class GraphicsPath; int m_flags; Point m_point; public: - Node(int type, const Point& point) - : m_flags(type & TypeMask) - , m_point(point) { } - int getType() const { return m_flags & TypeMask; } - bool isCloseFigure() const { return m_flags & CloseFigure ? true: false; } - Point& getPoint() { return m_point; } - const Point& getPoint() const { return m_point; } + Node(int type, const Point& point); + + int getType() const; + bool isCloseFigure() const; + void setCloseFigure(bool closeFigure); + Point& getPoint(); + const Point& getPoint() const; }; private: diff --git a/include/Vaca/base.h b/include/Vaca/base.h index 67e2a232..9e441fb3 100644 --- a/include/Vaca/base.h +++ b/include/Vaca/base.h @@ -49,7 +49,7 @@ namespace Vaca { #define VACA_VERSION 0 #define VACA_SUB_VERSION 0 -#define VACA_WIP_VERSION 6 +#define VACA_WIP_VERSION 7 /** * Defines the name and arguments that the main routine diff --git a/src/Dialog.cpp b/src/Dialog.cpp index 4017bc36..d81a8533 100644 --- a/src/Dialog.cpp +++ b/src/Dialog.cpp @@ -118,7 +118,8 @@ bool Dialog::preTranslateMessage(Message& msg) /** * Hides the dialog, but before changes the return state - * (setReturnState) to true, so doModal() returns true too. + * (setReturnState) to true, so #doModal returns true. + * * You can use this to bind the OK button action (Button::Action). * Example: * diff --git a/src/GraphicsPath.cpp b/src/GraphicsPath.cpp index d6205878..f9b1eb7d 100644 --- a/src/GraphicsPath.cpp +++ b/src/GraphicsPath.cpp @@ -38,6 +38,47 @@ using namespace Vaca; +////////////////////////////////////////////////////////////////////// +// + + +GraphicsPath::Node::Node(int type, const Point& point) + : m_flags(type & TypeMask) + , m_point(point) +{ +} + +int GraphicsPath::Node::getType() const +{ + return m_flags & TypeMask; +} + +bool GraphicsPath::Node::isCloseFigure() const +{ + return m_flags & CloseFigure ? true: false; +} + +void GraphicsPath::Node::setCloseFigure(bool state) +{ + if (state) + m_flags |= CloseFigure; + else + m_flags &= ~CloseFigure; +} + +Point& GraphicsPath::Node::getPoint() +{ + return m_point; +} + +const Point& GraphicsPath::Node::getPoint() const +{ + return m_point; +} + +////////////////////////////////////////////////////////////////////// +// GraphicsPath + GraphicsPath::GraphicsPath() { } diff --git a/src/Slider.cpp b/src/Slider.cpp index 4937d68d..49c7080c 100644 --- a/src/Slider.cpp +++ b/src/Slider.cpp @@ -34,11 +34,12 @@ #include "Vaca/Event.h" #include "Vaca/WidgetClass.h" #include +#include using namespace Vaca; -const int Slider::MinLimit = std::numeric_limits::min(); -const int Slider::MaxLimit = std::numeric_limits::max(); +const int Slider::MinLimit = SHRT_MIN; // std::numeric_limits::min(); +const int Slider::MaxLimit = SHRT_MAX; // std::numeric_limits::max(); Slider::Slider(Widget* parent, Style style) : Widget(WidgetClassName(TRACKBAR_CLASS), parent, style) diff --git a/src/String.cpp b/src/String.cpp index d582c4f2..46b2a524 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -33,6 +33,7 @@ #include "Vaca/Debug.h" #include #include +#include #include #include @@ -171,7 +172,7 @@ String String::format(const wchar_t* fmt, ...) va_list ap; va_start(ap, fmt); - int written = vsnwprintf(buf.get(), size, fmt, ap); + int written = _vsnwprintf(buf.get(), size, fmt, ap); va_end(ap); if (written == size) { diff --git a/src/Timer.cpp b/src/Timer.cpp index a9adfe54..06945eee 100644 --- a/src/Timer.cpp +++ b/src/Timer.cpp @@ -38,6 +38,7 @@ #include "Vaca/ConditionVariable.h" #include +#include // because MSVC using namespace Vaca; @@ -176,7 +177,7 @@ void Timer::run_timer_thread() { ScopedLock hold(timer_mutex); unsigned int start, end, period, delay; - unsigned int inf = std::numeric_limits::max(); + unsigned int inf = UINT_MAX; // std::numeric_limits::max(); std::vector::iterator it; Timer* timer;